;*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
;*
;*****************************************************************************/
;*****************************************************************************
; 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
        include tune.inc
;*****************************************************************************
; Equates                                                                    *
;*****************************************************************************

PSEUDOSTACKSIZE EQU 256 ;was 100

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

        .DATA

        ALIGN 4

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

        PUBLIC PseudoStackTop
PseudoStackTop LABEL DWORD                      ; Top of stack

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

        .CODE
_TUNE3 SEGMENT DWORD FLAT PUBLIC '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

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

        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
        MOV     pStackLimit,OFFSET PseudoStack+cb_variables_len+StackFirewall

        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

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

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
        XCHG    DH,AH                           ; over the color information.
        JMP     LCI_Exit

ALIGN 4
        PUBLIC  LoadAVioInfo
LoadAVioInfo::
        LODSW                                   ; For an AVio LVB we extract
        XOR     AH,AH
        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

        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

; 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]
        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

;/*
;** 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]
        PUSH    EDX
        NOT     EDX
        MOV     wLastAttributes,DX
        JMP     InterpretAttributes             ; Draw it!

ALIGN 4
        PUBLIC  DoVStripeMiddle
DoVStripeMiddle::
        MOV     AX,wFullRows                    ; Do we have any full-height
        OR      AX,AX                           ; cells in this border?
        JNZ     DoVStripeFC
        JMP     DoVStripeBottom

ALIGN 4
        PUBLIC  DoVStripeFC
DoVStripeFC::
        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
        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
        ADD     ESI,wVertLVBIncr
        CMP     EDI,EDX
        JNE     VBAttributesChanged

        PUBLIC  VBAttributesFixed
VBAttributesFixed::
        XCHG    ESI,EAX
        SHL     ESI,1
        PUSH    [EBX+ESI]
        MOV     ESI,EAX
        LOOP    VBScanLoop
        PUSH    EDI
        NOT     EDI
        MOV     wLastAttributes,DI
        JMP     InterpretAttributes

ALIGN 4
        PUBLIC  VBAttributesChanged
VBAttributesChanged::
        PUSH    EDI
        PUSHD   -1
        MOV     EDI,EDX
        JMP     SHORT VBAttributesFixed

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
        MOV     ESI,EAX
        SHL     ESI,1
        ADD     ESI,npcpmap
        PUSH    [ESI]
        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::
        ADD     DX,BX                   ; Undo sub DX,BX
        PUSH    EBX                     ; 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 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

        PUBLIC  LCID_Did_not_change
LCID_Did_not_change::
        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.
        add     esi,4                    ; Undo the LODSW side effects
        jmp     AVioSplitRow

ALIGN 4
        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

        PUBLIC  AVioEndOfRow
AVioEndOfRow::
        JMP     End_of_row

ALIGN 4
        PUBLIC  AVioSplitRow
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.
;*/

ALIGN 4
        PUBLIC  FCAttributeChange
FCAttributeChange::
        ADD     AH,BH                   ; Undo the sub AH,BH
        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
        ADD     ESI,2                   ; Undo the LODSW side effect

        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

        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

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.

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.

;/*
;** 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
        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::
        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
        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
_TUNE3 ENDS
        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

        END
