;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132

;/*****************************************************************************
;*
;* SOURCE FILE NAME = CellScan.asm
;*
;* DESCRIPTIVE NAME = Video cell scannning program
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/26/87
;*
;* DESCRIPTION  Routines for scanning logical video cells and constructing              
;*              pseudo code on the stack for drawing their images.
;*                                                                                      
;* FUNCTIONS    Public: DrawImageRect
;*                                    
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   06/26/87                     ronm  - Created
;*   ---------------- DrawImageRect: -----------------------------------------
;*   09/90                        rajivg
;*                                  Ported code for VIO scroll bitblt into
;*                                  this routine to make vio scroll faster.
;*                                  Removed some gp-faults and a clipping bug
;*                                  from the ported code.
;*   07/14/88                     Walt Moore [waltm]
;*                                  SS:BX now points to a RECTL instead of a
;*                                  RECTS.  Only .lo portion is guaranteed to
;*                                  be valid.
;*   06/29/87                     ronm
;*                                  Converting uses of SymbolDelta to word and
;*                                  byte multiplications.
;*   06/23/87                     ronm
;*                                  Code to redraw the mouse cursor after
;*                                  drawing more than a trivial number of
;*                                  characters.
;*
;*   04/17/87                     Ron Murray  [ronm]
;*                                  Correction to the code for drawing a
;*                                  single horizontal stripe which fits
;*                                  entirely within one cell row.  Corrected
;*                                  the code for drawing the top border.
;*                                  Corrected the rect passed to the exclude
;*                                  routine.
;*   04/08/87                     Ron Murray  [ronm]
;*                                  Adjustments to allow DrawImageRect to be
;*                                  driven by enumerate_clip_rects.
;*   03/16/87                     Ron Murray  [ronm]
;*                                  Merging the AVio support.
;*   02/24/87                     Ron Murray  [ronm]
;*                                  Fixed a     due to the last patch.  Code
;*                                  after the replaced div wCellHeight assumed
;*                                  that di contained wCellHeight.
;*   02/23/87                     Ron Murray  [ronm]
;*                                  Replaced mul wCellHeight by SymbolDelta.
;*                                  Replaced div wCellHeight by mul
;*                                  InvSymbolImageLines
;*   02/17/87                     Ron Murray  [ronm]
;*                                  Changed the FillRect calls to pass the bit
;*                                  array pointer.
;*   02/13/87                     Ron Murray [ronm] - Added time measurements.
;*   02/11/87                     Ron Murray [ronm] - Put symbol set in CS segment.
;*   02/09/87                     Ron Murray [ronm]
;*                                      Fix:  Added code to save ax from the
;*                                  effects of USMax in the border tests.
;*   02/03/87                     Ron Murray [ronm] - Wrote DrawImageRect
;*   ---------------- LoadCellInfo: -----------------------------------------
;*   12/15/87                     ronm
;*                                      Fix:  AVio cells weren't being loaded
;*                                  correctly.
;*   03/12/87                     Ron Murray [ronm] - Wrote LoadCellInfo
;*   ---------------- ScanVerticalBorder: -----------------------------------
;*   06/29/87                    ronm
;*                                 Converting uses of SymbolDelta to word and
;*                                 byte multiplications.  Corrections to the
;*                                 source address calculations for the ragged
;*                                 top of the vertical column.
;*   04/17/87                    Ron Murray [ronm]
;*                                 Fix to avoid clobbering the destination
;*                                 address for the ragged top of a vertical
;*                                 column.
;*   03/13/87                    Ron Murray [ronm] - Wrote ScanVerticalBorder
;*   ---------------- ScanFullCells: ----------------------------------------
;*   06/29/87                    ronm
;*                                 Converting uses of SymbolDelta to
;*                                 word and byte multiplications.
;*   03/13/87                    Ron Murray [ronm] Wrote ScanFullCells
;*   ---------------- SegmentHorizontalScanning: -----------------------------
;*   06/29/87                    ronm
;*                                 Converting uses of SymbolDelta to word and
;*                                 byte multiplications.
;*   05/13/87                    Ron Murray  [ronm]
;*                                 Correction to avoid use of initialized
;*                                 wSaveLCIDSelector.
;*   03/27/87                    Ron Murray [ronm]
;*                                 Wrote SegmentHorizontalScanning
;*****************************************************************************/

        .xlist

        include cmacros.inc
INCL_DEV            equ 1
INCL_AVIOP          equ 1
        include pmgre.inc
        include driver.inc
        include cellblt.inc
        include njmp.mac
        .list

        ??_out  cellscan


sBegin  VioSeg
        assumes cs,VioSeg

        externW     VioSegData
        externNP    InterpretAttributes

ifdef HW_BLT
        externFP    dev_ScrollRect
endif

sEnd    VioSeg

;/***************************************************************************
;*
;* 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 ss:bx.  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 SI will    
;*                 hold the frame pointer for CharRect.
;*
;*                 Registers Destroyed:
;*                       ?
;*                 Registers Preserved:
;*                       BP SI
;*                 Calls:
;*                       DrawVerticalBorders, DrawVerticalBorders, DrawFullCells 
;*
;* INPUT         = SS:BX -- a RECTL structure defining the portion of the 
;*                          screen to be painted.
;*                 SI    -- the stack frame pointer for CharRect.
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

sBegin  Code
        assumes cs,Code

cProc   DrawImageRect,<PUBLIC,NEAR>
cBegin
        call    far ptr far_DrawImageRect
cEnd

sEnd    Code

sBegin  VioSeg
        assumes cs,VioSeg

define_CharRect_frame far_DrawImageRect

;/*
;**         localW  wHeightGapHW
;*/
cBegin  <nogen>

;/*
;**   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 ss:bx 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    bp                      ; Preserve the frame pointer for
                                        ; EnumClipRects.

        mov     bp,si                   ; Retrieve the frame pointer for
                                        ; CharRect.

        mov     fSomethingDrawn,si      ; Log the fact that we've got a
                                        ; a non-null visible region.

        mov     ax,ss:[bx].rcl_xLeft.lo ; Copy the clip rectangle to our
        mov     rClipRect.rcs_xLeft,ax  ; stack frame.
        mov     ax,ss:[bx].rcl_yBottom.lo
        mov     rClipRect.rcs_yBottom,ax
        mov     ax,ss:[bx].rcl_xRight.lo
        mov     rClipRect.rcs_xRight,ax
        mov     ax,ss:[bx].rcl_yTop.lo
        mov     rClipRect.rcs_yTop,ax
ifdef HW_BLT
        push    bx                      ; So we can reference the original
endif;                                  ; clip rect later

        mov     ds,VioSegData             ; Restore access to our data segment.

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


        mov     di,wDestHeight          ; So we can flip the coordinate
        mov     dx,di                   ; origin to the top left corner.

        sub     di,rClipRect.rcs_pts1.pts_y   ; ... Bottom ...
        sub     dx,rClipRect.rcs_pts2.pts_y   ; ... Top    ...
        mov     cx,rClipRect.rcs_pts1.pts_x   ; ... Left   ...
        mov     si,rClipRect.rcs_pts2.pts_x   ; ... Right  ...
ifndef HW_CUR
        call    far_exclude
endif; HW_CUR

ifdef  HW_BLT

;/*
;**  The HW_BLT flag enables ScrollRect. The reason that it's done here
;**  is to save space and time. Here we call dev_ScrollRect (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, in this case -1.
;** 
;** 
;**            --------------------------------
;**            |                            | |
;**            |                            |A|
;**            |                            |r|
;**            |                            |e|
;**            |      BitBlt'd area         |a|
;**            |                            | |
;**            |       (worse case)         |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.
;*/

;/*
;**  Set up dev_ScrollRect call
;*/
        xor     cx,cx
        cmp     FunN.lo,off_ScrollRect
        njne    no_scroll_rect
        les     si,lpRectDesc
        assumes es,nothing

;/*
;** if we're redrawing the ENTIRE screen, let CharRect do it
;*/
        mov     cx,es:cellscroll_HorzMovement[si].lo
        sub     cx,es:cellscroll_RectWidth[si].lo
        njz     no_scroll_rect
        mov     cx,es:cellscroll_VertMovement[si].lo
        sub     cx,es:cellscroll_RectDepth[si].lo
        njz     no_scroll_rect


;/*
;** Make dev_ScrollRect call
;*/
        mov     ax,es:cellscroll_StartColumn[si].lo
        mul     wCellWidth
        sub     ax,wHorzPixelOffset
        push    ax          ; X1
        xor     ax,ax
        sub     ax,wVertLineOffset
        push    ax          ; Y1
        mov     ax,es:cellscroll_HorzMovement[si].lo
        mul     wCellWidth
        push    ax          ; delta X
        mov     ax,es:cellscroll_VertMovement[si].lo
        mul     wCellHeight
        push    ax          ; delta Y
        mov     ax,es:cellscroll_RectWidth[si].lo
        mul     wCellWidth
        push    ax          ; width
        mov     ax,es:cellscroll_RectDepth[si].lo
        mul     wCellHeight
        push    ax          ; height
        push    ss
        lea     ax,rClipRect
        push    ax          ; lpClipRect
        cCall   dev_ScrollRect

        mov     wHeightGapHW,ax   ; ax is output from dev_scrollrect

;/*
;** Adjust clip rect for "Area A" from the vert scroll
;*/
        xor     cx,cx
        mov     ax,es:cellscroll_VertMovement[si].lo
        or      ax,ax
        jz      done_with_vert
        mov     di,wCellHeight
        mul     di
        mov     bx,ax
        xor     ax,ax
        sub     ax,wVertLineOffset

;/*
;**  ax = Y screen Coord bx = Delta Y in Screen Coords
;**  di = cell height
;*/

        or      bx,bx
        js      @f
        mov     ax,wDestHeight
        sub     ax,rClipRect.rcs_pts2.pts_y
        add     ax,bx
        mov     bx,wDestHeight
        sub     bx,rClipRect.rcs_pts1.pts_y ;bottom
        USMin   bx,ax,dx
        mov     ax,bx
        mov     bx,wDestHeight
        sub     bx,ax
        mov     rClipRect.rcs_pts1.pts_y,bx
        mov     cx,-1
        jmp     short done_with_vert
@@:
        mov     cx,ax
        add     cx,bx
        mov     ax,es:cellscroll_RectDepth[si].lo
        mul     di
        add     ax,cx               ;ax=bottom
        mov     cx,wDestHeight
        sub     cx,rClipRect.rcs_pts1.pts_y ;top

;/*
;** ax=bottom scan of scroll; bx=delta x; cx=bottom clip
;*/

        cmp     ax,cx
        jl      @f
        mov     ax,cx
        add     ax,bx
@@:
        mov     bx,wDestHeight
        sub     bx,rClipRect.rcs_pts2.pts_y ;top
        SMax    bx
        mov     ax,wDestHeight
        sub     ax,bx
        add     ax,wHeightGapHW
        cmp     ax,rClipRect.rcs_pts2.pts_y
        jge     @f
        mov     rClipRect.rcs_pts2.pts_y,ax

@@:
        mov     cx,-1
done_with_vert:

;/*
;** Adjust clip rect for "Area B" from the horz scroll
;*/
        mov     ax,es:cellscroll_HorzMovement[si].lo
        or      ax,ax
        jz      no_horz_scroll_rect
        mul     wCellWidth
        mov     bx,ax
        mov     ax,es:cellscroll_StartColumn[si].lo
        mul     wCellWidth
        sub     ax,wHorzPixelOffset
;/*
;** ax = x pixel coord bx = pixel x delta
;*/
        or      bx,bx
        js      @f
        mov     di,rClipRect.rcs_pts1.pts_x
        USMax   ax,di,dx
        mov     bx,ax
        or      cx,cx
        jnz     done_with_horz2
        mov     rClipRect.rcs_pts1.pts_x,bx
        jmp     short no_horz_scroll_rect
@@:
        mov     di,ax
        mov     ax,es:cellscroll_RectWidth[si].lo
        mul     wCellWidth
        add     ax,di
        mov     di,rClipRect.rcs_pts2.pts_x
        USMin   ax,di,dx
        mov     bx,ax
        or      cx,cx
        jnz     done_with_horz1
        mov     rClipRect.rcs_pts2.pts_x,bx
        jmp     short no_horz_scroll_rect
done_with_horz2:
        mov     ax,es:cellscroll_HorzMovement[si].lo
        pop     si
        push    ss:[si].rcl_xLeft.lo
        push    bx
        jmp     short push_yn
done_with_horz1:
        mov     ax,es:cellscroll_HorzMovement[si].lo
        pop     si
        push    bx
        push    ss:[si].rcl_xRight.lo

;/*
;** Push our Y's (They're the same for either case.)
;*/
push_yn:
        or      ax,ax
        jns     @f
        push    rClipRect.rcs_pts2.pts_y
        push    ss:[si].rcl_yTop.lo
        push    cx
        jmp     short continue_with_DIR
@@:
        push    ss:[si].rcl_yBottom.lo
        push    rClipRect.rcs_pts1.pts_y
        push    cx
        jmp     short continue_with_DIR

no_horz_scroll_rect:
        xor     cx,cx
no_scroll_rect:
        pop     ax ;clean up stack
        push    cx

continue_with_DIR:
endif; HW_BLT

        mov     si,wDestHeight          ;** So we can flip the coordinate
                                        ;** origin to the top left corner.
        mov     ax,si
        sub     ax,rClipRect.rcs_pts1.pts_y   ; ... Bottom ...
        add     ax,wVertLineOffset      ;** Convert to LVB image coordinates.
        mov     di,ax
        mov     bx,wCellHeight
        xor     dx,dx
        div     bx
        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     cx,ax
        mul     bx
        sub     di,ax
        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     ax,si
        sub     ax,rClipRect.rcs_pts2.pts_y   ;** ... Top ...
        add     ax,wVertLineOffset            ;** Convert to LVB image coordinates.
        mov     di,ax
        add     ax,bx
        dec     ax
        div     bx
        mov     wTopRow,ax              ;** LVB row index for the first
                                        ;** row not clipped vertially.
        sub     cx,ax
        mov     wFullRows,cx            ;** The number of rows in the
                                        ;** FULL region (possibly zero).
        mul     bx
        sub     di,ax
        neg     di
        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     ax,rClipRect.rcs_pts2.pts_x   ;** ... Right ...
        add     ax,wHorzPixelOffset     ;** Convert to LVB image coordinates.
        mov     cx,ax
        PixToCol    ax
        mov     wRightCol,ax            ;** Right limit on the LVB column
                                        ;** set which is not clipped
                                        ;** horizontally.  Like RECT.right,
                                        ;** this defines a boundary, not
                                        ;** an index.
        mov     di,ax
        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
                                        ;** of the full cell region.


        mov     ax,rClipRect.rcs_pts1.pts_x   ;** ... Left ...
        add     ax,wHorzPixelOffset     ;** Convert to LVB image coordinates.
        mov     cx,ax
        add     ax,wCellWidth
        dec     ax
        PixToCol    ax
        mov     wLeftCol,ax             ;** LVB index of the leftmost column
                                        ;** of the LVB which is not clipped
                                        ;** horizontally.
        sub     di,ax
        mov     si,di
        mov     wFullCols,di            ;** 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     si,cl                   ;** A LVB pointer increment used to
        sub     si,wLVBRowBytes         ;** move from the front of an LVB row
        mov     wLVBRowInc,si           ;** to the end of the next row above.


        mov     si,wCellSize            ;** An LVB address increment for
        sub     si,wLVBRowBytes         ;** moving vertically.
        mov     wVertLVBIncr,si


        xor     di,di                   ;** Base offset for the Logical
                                        ;** Video Buffer.

        mov     ax,wTopRow
        mov     si,wColCount
        mul     si
        add     ax,wLeftCol
        shl     ax,cl
        add     ax,di
        mov     pFirstFullLVBCell,ax    ;** The LVB offset for the top left
                                        ;** cell in the FULL region.
        mov     ax,wBotRow
        dec     ax
        mul     si
        add     ax,wRightCol
        shl     ax,cl
        add     ax,di
        dec     ax
        dec     ax
        mov     pLastFullLVBCell,ax     ;** Address of the last LVB word
                                        ;** at the bottom right corner of the
                                        ;** FULL region.

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

        PUBLIC  StackCalculations

StackCalculations:

        mov     bx,cb_variables_len+StackFirewall
        mov     pStackLimit,bx

        mov     ax,sp                   ;** Where the return address
        sub     ax,StackCallOverhead    ;** used by the Scan functions
        mov     pReturnAddress,ax       ;** 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.
;*/

                                        ;** Set a flag to mark the first
                                        ;** segment of processing for the
        mov     wfForceColors,0ffffh    ;** current rectangle.

        mov     cx,wFullCols            ;** Checking width boundary
        or      cx,cx                   ;** conditions.  When wFullCols is
        js      OneColumn               ;** negative, the left and right
        jmp     DoLeftBorder            ;** borders overlap to form a single
                                        ;** vertical stripe.

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     ax,pFirstFullLVBCell
        sub     ax,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,ax

        mov     ax,pLastFullLVBCell
        add     ax,wCellSize            ;** Adjust to the next cell.
        mov     pLastLVBCell,ax

        call    near ptr ScanVerticalBorder

        jmp     RectDone

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     ax,pFirstFullLVBCell
        sub     ax,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,ax

        mov     ax,pLastFullLVBCell
        mov     bx,wFullCols
        mov     cx,wCellSizeShift
        shl     bx,cl
        sub     ax,bx
        mov     pLastLVBCell,ax

        call    near ptr ScanVerticalBorder


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     ax,pFirstFullLVBCell
        mov     bx,wFullCols
        mov     cx,wCellSizeShift
        shl     bx,cl
        add     ax,bx

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

        add     ax,wCellSize
        sub     ax,2

        mov     pFirstLVBCell,ax

        mov     ax,pLastFullLVBCell
        add     ax,wCellSize
        mov     pLastLVBCell,ax

        call    near ptr ScanVerticalBorder


DoMiddleColumns:

        mov     cx,wFullCols
        or      cx,cx
        jnz     GotFullCells
        jmp     RectDone


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     ax,pFirstFullLVBCell
        sub     ax,wLVBRowBytes
        mov     pFirstLVBCell,ax

        mov     bx,wFullCols
        mov     cx,wCellSizeShift
        shl     bx,cl
        add     ax,bx
        sub     ax,2
        mov     pLastLVBCell,ax
        mov     si,ax

        mov     ax,wTopFullLine
        mov     bx,wTopLines
        sub     ax,bx
        mov     ycoordTopLeft,ax

        mov     ax,wCellHeight
        sub     ax,bx
        mov     wTopLineOffset,ax

        mov     bx,wBotLines
        sub     bx,ax
        mov     wScanLineCount,bx
        mov     cx,wFullCols

        call    near ptr ScanFullCells
        jmp     RectDone


MultipleMiddleRows:

        mov     ax,wTopLines
        or      ax,ax
        jz      DoFullCells

        mov     bx,wTopFullLine
        sub     bx,ax
        mov     ycoordTopLeft,bx
        mov     bx,wCellHeight
        sub     bx,ax
        mov     wTopLineOffset,bx
        mov     wScanLineCount,ax

        mov     ax,pFirstFullLVBCell
        sub     ax,wLVBRowBytes
        mov     pFirstLVBCell,ax

        mov     bx,wFullCols
        mov     cx,wCellSizeShift
        shl     bx,cl
        add     ax,bx
        sub     ax,2
        mov     pLastLVBCell,ax
        mov     si,ax
        mov     cx,wFullCols

        call    near ptr ScanFullCells

DoFullCells:

        mov     bx,wFullRows
        or      bx,bx
        jz      DoBottomBorder

        xor     ax,ax
        mov     wTopLineOffset,ax
        mov     ax,wCellHeight
        mov     wScanLineCount,ax
        mov     ax,wTopFullLine
        mov     ycoordTopLeft,ax

        dec     bx
        mov     cx,wFullCols
        mov     ch,bl

        mov     si,pLastFullLVBCell

        call    near ptr ScanFullCells

DoBottomBorder:

        mov     ax,wBotLines
        or      ax,ax
        jz      RectDone

        mov     wScanLineCount,ax

        xor     ax,ax
        mov     wTopLineOffset,ax

        mov     ax,wBotFullLine
        mov     ycoordTopLeft,ax

        mov     ax,pLastFullLVBCell
        add     ax,wLVBRowBytes
        mov     si,ax
        mov     pLastLVBCell,ax
        mov     bx,wFullCols
        mov     cx,wCellSizeShift
        shl     bx,cl
        sub     ax,bx
        inc     ax
        inc     ax
        mov     pFirstLVBCell,ax

        mov     cx,wFullCols

        call    near ptr ScanFullCells

RectDone:
ifdef HW_BLT

;/*
;** Check to see if we have another clip rect to do.
;*/
        pop     ax          ;** 0=done
        or      ax,ax
        jz      no_saved_cliprect
        pop     rClipRect.rcs_pts2.pts_y
        pop     rClipRect.rcs_pts1.pts_y
        pop     rClipRect.rcs_pts2.pts_x
        pop     rClipRect.rcs_pts1.pts_x
        push    0
        jmp     continue_with_DIR
no_saved_cliprect:
endif; 
ifndef HW_CUR
        call    far_unexclude
else
        mov     ds,VioSegData
        assumes ds,Data
endif; HW_CUR

        cCall   MoveCursor,<8000h,8000h>        ;** actually a CheckCursor call

        mov     si,bp                   ;** Restore SI and BP to the values
        pop     bp                      ;** they had on entry.

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


        mov     ax,sp
        ret_far

cEnd    <nogen>


;/***************************************************************************
;*
;* 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         = DS:SI -- points to the last word of the cell to scan. 
;*                 FLAGS -- STD is assumed.
;* OUTPUT        = None
;*
;* RETURN-NORMAL = 
;*      DX -- will be the offset within the current symbol set of the
;*            character image referenced by the cell.
;*      BX -- will hold the attribute information for the cell.  The
;*            bit fields therein are given by the masks AVioColorSetMask,
;*            etc.
;*      SI -- will be decremented to point to the last word of the
;*            next cell to scan.
;* RETURN-ERROR  = None
;*
;**************************************************************************/

define_CharRect_frame LoadCellInfo

cBegin  <nogen>

        mov     ax,1                    ;** Are we scanning an AVio
        cmp     ax,wCellSizeShift       ;** logical video buffer?
        jb      LoadAVioInfo

        xor     dx,dx                   ;** If not, zero the extra AVio
        lodsw                           ;** attribute bits, and copy
        xchg    dh,ah                   ;** over the color information.

        ret_near


LoadAVioInfo:

        lodsw                           ;** For an AVio LVB we extract
        xor     ah,ah
        mov     dx,ax                   ;** the attribute information
        lodsw                           ;** and put the extra control
        xchg    ah,dh                   ;** bits in BL.

        ret_near

cEnd    <nogen>


;/***************************************************************************
;*
;* 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 = ? Values returned in registers       
;* RETURN-ERROR  = ? Values returned in regs for errors 
;*
;**************************************************************************/

define_CharRect_frame ScanVerticalBorder

cBegin  <nogen>

        mov     ax,wFullRows            ;** check to see if this vertical
        or      ax,ax                   ;** border fits completely into
        jns     MultipleVStripeRows     ;** a single cell.

        std
        mov     es,VioSegData

        mov     ax,wTopFullLine
        mov     bx,wTopLines
        sub     ax,bx
        mov     ycoordStart,ax

        mov     ax,wCellHeight
        sub     ax,bx
        mov     wTopLineOffset,ax
        mov     bx,wBotLines
        sub     bx,ax
        mov     wScanLineCount,bx

        PushRet ax,VStripeDone

        mov     ds,seg_LVB
        mov     si,pFirstLVBCell
        sub     si,wLVBRowBytes
        call    near ptr LoadCellInfo

        and     dx,(NOT AVioUnderscoreMask) ;** Because we know the bottom line
                                            ;** is not included in this image.

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

        mov     si,ax
        shl     si,1
        add     si,npcpmap
        push    es:[si]

        push    dx
        not     dx
        mov     wLastAttributes,dx

        jmp     InterpretAttributes



MultipleVStripeRows:

        mov     ax,wTopLines            ;** Check for a ragged edge on
        or      ax,ax                   ;** the top of the column.
        jz      DoVStripeMiddle

        std
        mov     es,VioSegData

        mov     wScanLineCount,ax       ;** Scan lines to draw.
        mov     bx,wTopFullLine
        sub     bx,ax
        mov     ycoordStart,bx
        mov     bx,wCellHeight
        sub     bx,ax
        mov     wTopLineOffset,bx

        PushRet dx,DoVStripeMiddle      ;** Set our return point.

        mov     ds,seg_LVB
        mov     si,pFirstLVBCell        ;** Load the image address and
        sub     si,wLVBRowBytes         ;** attribute information for
        call    near ptr LoadCellInfo   ;** this cell.

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

        xchg    si,ax
        shl     si,1
        add     si,npcpmap
        push    es:[si]

        push    dx
        not     dx
        mov     wLastAttributes,dx

        jmp     InterpretAttributes     ;** Draw it!


DoVStripeMiddle:

        mov     ax,wFullRows            ;** Do we have any full-height
        or      ax,ax                   ;** cells in this border?
        jnz     DoVStripeFC
        jmp     DoVStripeBottom


DoVStripeFC:

        std
        mov     es,VioSegData
        mov     cx,ax
        mov     si,pLastLVBCell
        mov     ax,wTopFullLine
        mov     ycoordStart,ax
        mov     bx,wCellHeight
        mov     wScanLineCount,bx
        mov     wTopLineOffset,0

        mov     ds,seg_LVB

        mov     bx,si

        call    near ptr LoadCellInfo

        mov     si,bx
        mov     di,dx
        mov     bx,npcpmap

        PushRet ax,DoVStripeBottom

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

VBScanLoop:

        call    near ptr LoadCellInfo
        add     si,wVertLVBIncr
        cmp     di,dx
        jne     VBAttributesChanged

VBAttributesFixed:

        xchg    si,ax
        shl     si,1
        push    es:[bx+si]
        mov     si,ax

        loop    VBScanLoop

        push    di
        not     di
        mov     wLastAttributes,di

        jmp     InterpretAttributes


VBAttributesChanged:

        push    di
        push    -1
        mov     di,dx

        jmp     SHORT VBAttributesFixed


DoVStripeBottom:

        mov     ax,wBotLines            ;** Check for a ragged edge on
        or      ax,ax                   ;** the bottom of the column.
        jz      VStripeDone

        std
        mov     es,VioSegData

        mov     wScanLineCount,ax
        mov     wTopLineOffset,0
        mov     ax,wBotFullLine
        mov     ycoordStart,ax

        PushRet cx,VStripeDone

        mov     ds,seg_LVB
        mov     si,pLastLVBCell
        add     si,wLVBRowBytes
        call    near ptr LoadCellInfo

        and     dx,(NOT AVioUnderscoreMask) ;** Because we know the bottom line
                                            ;** is not included in this image.
        mov     si,ax
        shl     si,1
        add     si,npcpmap
        push    es:[si]
        push    dx
        not     dx
        mov     wLastAttributes,dx

        jmp     InterpretAttributes


VStripeDone:

        ret_near

cEnd    <nogen>

;/***************************************************************************
;*
;* 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
;*                 Calls:
;*                       InterpretAttributes
;*
;* INPUT         =
;*      Assumes the following stack frame variables:
;*
;*          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.
;*
;*      and the following register state:
;*
;*          CH  -- Rows-1
;*          CL  -- Columns
;*          SI  -- offset to the last LVB word in the row/column rectangle.
;* OUTPUT        = None
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

define_CharRect_frame ScanFullCells

cBegin  <nogen>

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


        mov     bx,VioSegOFFSET FCNextCell
        mov     ax,wCellSizeShift
        shr     ax,1
        jz      SaveFCCodePointer
        mov     bx,VioSegOFFSET AVioFCNextCell

SaveFCCodePointer:

        mov     npNextCellLabel,bx

;/*
;**  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:
;** 
;**        AH/AL   -- will be destroyed.
;**        BX      -- holds the previous display attributes.
;**        CH      -- holds the number of rows remaining to process.
;**        CL      -- holds the number of columns to process in the
;**                      current row.
;**        DX      -- will hold the current attributes for AVio cells.
;**     DS:SI      -- points to an LVB cell.
;**        DI      -- holds a lower limit on SP.
;**     SS:SP      -- points to the first item in the pseudo code list.
;**     ES:BP      -- points to the 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.
;*/

        public  AVioFCAttributeChange
AVioFCAttributeChange:

        add     dx,bx                   ;** Undo sub dx,bx
        push    bx                      ;** Push the old attributes.
        push    -1                      ;** Push a control flag marker.
        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 BP to point to the code page
;**  mapping vector for the new LCID
;*/


        push    si
        mov     si,AVioLCIDMask
        and     si,dx
        shl     si,1
        mov     bp,ss:[cb_BPSaveSlot]

        mov     si,wSymbolSetOffsets[si]
        mov     npcpmap,si              ;** remember this mapping vector as
        mov     bp,si                   ;**   current map in case BP trashed
        pop     si


lcid_did_not_change:

        mov     bx,dx                   ;** OldAttributes <- NewAttributes
        xor     dx,dx



        cmp     sp,di                   ;** If we haven't filled the stack,
        ja      AVioFCAttributesFixed   ;** resume the scanning process.

        add     si,4                    ;** Undo the LODSW side effects
        jmp     AVioSplitRow


        public  AVioFCNextCell
AVioFCNextCell:

        cmp     sp,di                   ;** Did we run out of stack space?
        jbe     AVioSplitRow

        lodsw                           ;** Load the second word of an
        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 es:bp.  We push that glyph index
;** as part of the pseudo code.
;*/

        xchg    ax,si
        shl     si,1
        push    es:[bp+si]
        mov     si,ax

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 es:bp.  We push that glyph index
;** as part of the pseudo code.
;*/

        xchg    ax,si
        shl     si,1
        push    es:[bp+si]
        mov     si,ax

            ENDM


        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


AVioEndOfRow:

        jmp     end_of_row


AVioSplitRow:

        jmp     split_a_row


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

FCAttributeChange:

        add     ah,bh                   ;** Undo the sub ah,bh
        mov     al,bl                   ;** Save wLVBRowIncr
        xor     bl,bl                   ;** Zot the AVio attribute bits
        push    bx                      ;** Store the previous attributes
        push    -1                      ;** Push a control mark (-1).
        mov     bx,ax                   ;** Save the new color attributes
                                        ;** and retrieve wLVBRowIncr
        add     si,2                    ;** Undo the LODSW side effect


FCNextCell:

        cmp     sp,di                   ;** Did we run out of stack space?
        jbe     VioSplitRow

        lodsw                           ;** 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 es:bp.  We push that glyph index
;** as part of the pseudo code.
;*/

        xchg    ax,si
        shl     si,1
        push    es:[bp+si]
        mov     si,ax


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 es:bp.  We push that glyph index
;** as part of the pseudo code.
;*/

        xchg    ax,si
        shl     si,1
        push    es:[bp+si]
        mov     si,ax

            ENDM


        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


VioEndOfRow:

        jcxz    VioSplitRow
        push    -2
        mov     cl,bl
        dec     ch
        add     si,dx
        jmp     SHORT FCNextCell


VioSplitRow:

        xor     bl,bl
        jmp     SHORT split_a_row

cEnd    <nogen>


;/***************************************************************************
;*
;* 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 = ? Values returned in registers       
;* RETURN-ERROR  = ? Values returned in regs for errors 
;*
;**************************************************************************/

define_CharRect_frame SegmentHorizontalScanning

cBegin  <nogen>

end_of_row:

;/*
;**  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     bp,ss:[cb_BPSaveSlot]   ;** The code below needs the
                                        ;** stack frame.

        jcxz    draw_cell_images        ;** Have we finished the matrix?

        add     si,wLVBRowInc           ;** Move SI to the rightmost cell
                                        ;** of the next LVB row.
        dec     ch                      ;** Decrement the rows remaining.

        mov     cl,BYTE PTR wFullCols   ;** Set up the column count again.

        push    -2

        mov     ax,npNextCellLabel

        mov     bp,npcpmap              ;** set up BP for the loop,
        jmp     ax                      ;** Then resume scanning.


split_a_row:

        mov     bp,ss:[cb_BPSaveSlot]   ;** The code below needs the
                                        ;** stack frame.

draw_cell_images:

;/*
;**  The phase 2 code makes the following register assumptions:
;** 
;**        AX      -- will be destroyed.
;**        BX      -- holds the increment to move DI rightward to one cell image.
;**        DX      -- holds the scan line increment for DI.
;**        SI      -- used to retrieve pseudo code and glyph images.
;**        DI      -- points to the next destination byte.
;**        SP      -- points to the first pseudo code syllable to process.
;**        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.
;**        FLAGS   -- Direction flag must be reset.
;** 
;**  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    bx                      ;** Push the attributes for the
                                        ;** first cells in the stream.

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

        not     bx
        mov     wLastAttributes,bx

        xor     ax,ax                   ;** Zot the flag so we don't do
        mov     wfForceColors,ax        ;** this for any trailing segments.


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


segmented_drawing:

        mov     wSaveCounts,cx          ;** Save the registers we'll need
        mov     pCell,si                ;** after phase 2.

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


        mov     ax,wScanLineCount
        mul     ch
        add     ycoordStart,ax
        xor     ax,ax
        mov     al,cl
        mul     bCellWidth
        add     xcoordStart,ax

        mov     ax,VioSegOFFSET restart_horz_lvb_scan ;** Adjust the return point
        mov     bx,pReturnAddress                     ;** for this drawing pass.
        mov     ss:[bx],ax

        jmp     InterpretAttributes


restart_horz_lvb_scan:

        mov     cx,wSaveCounts          ;** Restore the registers for
        mov     si,pCell                ;** phase 1 processing.


start_horz_lvb_scan:

        mov     di,pStackLimit
        mov     ds,seg_LVB

        mov     bx,[si]                 ;** 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 ax,HorzCellsDrawn       ;** Set the return address
                                        ;** optimistically
        mov     ax,npNextCellLabel

        mov     es,VioSegData           ;** Set up addressablity to the
        mov     bp,npcpmap              ;** code page mapping vector,

        jmp     ax                      ;** and go back into the fray.


        public  restore_avio_attr
restore_avio_attr:
                                        
        mov     ax,[si-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
        xor     dx,dx                   ;** Assumed for AVio full cells
        jmp     resume_scanning


HorzCellsDrawn:                         ;** All the full cells have been drawn.

        ret_near

cEnd    <nogen>

sEnd    VioSeg
end
