;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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 = CELLBLT.ASM
;*
;* DESCRIPTIVE NAME = Implementation of the driver interfaces for VIO/AVIO.
;*
;*
;* VERSION      V2.0
;*
;* DATE         01/26/87
;*
;* DESCRIPTION
;*
;*  This module contains the entry points for the device driver code which
;*  supports Vio and AVio presentation spaces.  It invokes routines in the
;*  CellScan module which in turn invokes routines in the CellDraw module.
;*
;*
;*  All the character drawing work is funneled through the CharRect routine.
;*  CharRect establishes the stack frame used by the drawing and scanning
;*  routines, maps an LVB character rectangle into a pixel rectangle in
;*  screen coordinates, and then invokes DrawImageRect by way of
;*  enumerate_clip_rects.  DrawImageRect analyzes the clip rectangle it
;*  receives into a number of drawing regions characterized by the kinds of
;*  clipping required, and invokes the scanning routines in CELLSCAN.ASM to
;*  scan the LVB cells in those regions and get them drawn.  The scanning
;*  routines push on the stack a pseudocode description of the drawing
;*  actions necessary to materialize a portion of the image, and then invoke
;*  the drawing functions of CELLDRAW.ASM to interpret that pseudocode.
;*
;*
;* FUNCTIONS   CheckCodePage
;*             InvertTextCursor
;*             InvertSplitCursor
;*             CharStr
;*             UpdateCursor
;*             DeviceSetAVIOFont2
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   02/08/87                     Ron Murray  [ronm]
;*                                Added the parameters lpFont, lpDestBitmap,
;*                                lpScreenClientRect.  That was necessary to get
;*                                around the limitations of dynamic linking.  In
;*                                essence, Display.drv can't dynlink to GDI or
;*                                USER.
;*   02/11/87                     Ron Murray  [ronm] Put symbol set in CS segment.
;*   02/13/87                     Ron Murray  [ronm]
;*                                Added local wFullCell for use by SetDrawFn and
;*                                DrawImageColumn.
;*                                Ron Murray  [ronm] Added time measurements.
;*   02/23/87                     Ron Murray  [ronm]
;*                                Replaced mul wCellHeight by SymbolDelta.
;*                                Ron Murray  [ronm] Removed the parameter lpFont.
;*   02/24/87                     Ron Murray  [ronm]
;*                                    fix:  Clipping to the Client rect now uses
;*                                SMin/SMax instead of USMin/USMax.
;*   02/26/87                     Ron Murray  [ronm]
;*                                Converted to work in the EGA Hi-Res environment.
;*                                Ron Murray  [ronm]
;*                                Corrected the test for a Null client rect
;*                                pointer.
;*   02/27/87                     Ron Murray  [ronm]
;*                                Adjusted for the Ega Hires environment.
;*   03/11/87                     Ron Murray  [ronm]
;*                                Code to Coerce the Rect Descriptor to lie within
;*                                the LVB.
;*   03/28/87                     Ron Murray  [ronm]
;*                                Moved InvertClippedRect to CellDraw.asm.
;*   03/30/87                     Ron Murray [ronm]
;*                                Checked into \\Windows\core\slm
;*                                Displays\...\EgaHiRes
;*   04/07/87                     Ron Murray  [ronm]
;*                                Changed the parameter structure to match the
;*                                Winthorn call conventions.
;*                                Ron Murray  [ronm]
;*                                Added code to enumerate clip rectangles from the
;*                                visible region.
;*   04/16/87                     Ron Murray  [ronm]
;*                                Added wDest2ndFullIncr local to allow
;*                                wDest2ndIncr to be transient.
;*   06/05/87                     Ron Murray  [ronm]
;*                                Patches to change all LVB coordinates to be
;*                                relative to the bottom left corner of the LVB.
;*                                This applies to the Window Origin fields in the
;*                                PS and to all the descriptor parameters passed.
;*                                to CharRect.
;*   06/19/87                     Ron Murray  [ronm]
;*                                Added code to exclude the text cursor from the
;*                                rectangle to be drawn.
;*   06/29/87                     Ron Murray  [ronm]
;*                                Changing references to SymbolDelta to multiply
;*                                by wCellHeight.  This is necessary to support
;*                                multiple symbol heights.
;*   07/07/87                     Ron Murray [ronm]
;*                                Added CodepageID field to the presentation
;*                                space.
;*   07/09/87                     Ron Murray  [ronm]
;*                                Added support for multiple code pages and
;*                                multiple cell heights.
;*                                Ron Murray  [ronm]
;*                                Support for multiple code pages and multiple
;*           t                    cell heights.
;*   07/18/87                     Ron Murray  [ronm]
;*                                Adjusted to match the new dispatching interface.
;*                                Ron Murray  [ronm]
;*                                Adjusted to match the new dispatcher interface.
;*                                Ron Murray  [ronm]
;*                                Adjusted to match the new dispatcher interface.
;*                                Ron Murray  [ronm]
;*                                Adjusted the calls to CharRectGlue to match the
;*                                new (DCR 799) conventions of bottom left origin.
;*                                Ron Murray  [ronm]
;*                                Adjustments to match the new dispatching
;*                                interface.  Merged UpdateCursor with
;*                                Do_UpdateCursor.
;*   10/08/87                     Ron Murray  [ronm]
;*                                When TextCursorWidth == 0, coerce it to be
;*                                CellWidth.
;*   11/03/87                     Ron Murray  [ronm]
;*                                Adjusted to get the default cell image shape
;*                                from adDevCapsData
;*   02/22/88                     Charles Whitmer [chuckwh]
;*                                Now gets the DC origin directly form the DDC.
;*                                Charles Whitmer [chuckwh]
;*                                Made it take the DC origin directly from the
;*                                DDC.
;*   09/18/89                     johnc Implemented DCR25071
;*****************************************************************************/


        .xlist
        include cmacros.inc
INCL_DOSERRORS          equ     1
INCL_GRE_XFORMS         equ     1
INCL_GRE_BITMAPS        equ     1
INCL_GRE_STRINGS        equ     1
INCL_GRE_DCS            equ     1
INCL_GRE_DEVMISC1       equ     1
INCL_DEV                equ     1
INCL_DDICOMFLAGS        equ     1
INCL_FONTFILEFORMAT     equ     1
INCL_GRE_CLIP           equ     1
INCL_GPIREGIONS         equ     1
INCL_AVIOP              equ                      1

        include pmgre.inc
DINCL_VIO       equ     1
        include driver.inc
        include fontseg.inc
        include cellblt.inc
        include njmp.mac
        include 8514.inc
        .list

        ??_out  cellblt

        errcode <INV_HDC,INV_SETID,FONT_NOT_LOADED>
        errcode <INV_CODEPAGE,INV_FONT_ATTRS>

sBegin  Data

        externB fGrimReaper
        externW adDevCapsData
        externW default_vio_cpid    ; The meaning of code page zero...

        externQ adDevVioCells
        externA cDevVioCells
        externQ pDefVioFont

sEnd    Data

        externFP    DosCallback
        externFP    ring3_VioGetPSAddress
        externFP    GreEntry4
        externFP    ValidateSelector
        externFP    far_InnerAccumulateBounds

sBegin  VioSeg
        assumes cs,VioSeg

        externW     VioSegData

        externNP    Force_Valid_CP
        externNP    SetDisplayDefaults
        externNP    DrawImageRect
        externNP    InvertClippedRect


;/***************************************************************************
;*
;* FUNCTION NAME = CheckCodePage
;*
;* DESCRIPTION   = This routine looks at the CellImageHeight and CodepageID fields
;*                 of a Vio presentation space (*pVioPS) and determines the
;*                 correct code page and cell size to use for drawing cell images.
;*                 The parameters pSelectors and pOffsets, respectively, are
;*                 offsets to tables of font selectors and a table of offsets
;*                 to code page mapping vector offsets. The two tables determine
;*                 how (A)Vio cells are drawn.  The entries in the tables
;*                 correspond to a base symbol set (0) and three loadable symbol
;*                 sets (1..3).
;*
;*                 On exit the selector and offset tables will be usable by the
;*                 (A)Vio drawing functions.  In particular the font selector and
;*                 mapping vector offset for the base symbol set will be coerced
;*                 to valid values.
;*
;*                 This routine is only called by CharRect and UpdateCursor.
;*
;* INPUT         = C Prototype:
;*                   errVal _syscall CheckCodePage(VioPresentationSpace32 * pVioPS,
;*                                                 WORD                 * pSelectors,
;*                                                 WORD                 * pOffsets);
;*
;*                    where:
;*                      pVioPS     --> The desired VIO presentation space.
;*                      pSelectors --> Font definition.
;*                      pOffsets   --> Table of code page mapping vector offsets.
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc Check_Code_Page,<PUBLIC,NEAR>,<bx,cx,dx,si,di,ds,es>

        parmD   lpVioPS
        parmW   npSelectors
        parmW   npOffsets

        localW  cp
cBegin

;/*
;** First we coerce the code page for the base symbol set to a valid
;** id.  Note that zero is a valid id.  It stands for the default code
;** page as defined by DosGetCtryInfo.  That default is interrogated
;** during display initialization and kept in the global constant
;** default_vio_cpid.
;*/

        les     bx,lpVioPS
        mov     ax,es:viops_CodepageID[bx]
        or      ax,ax
        jnz     non_default_cpid

        mov     ax,default_vio_cpid


non_default_cpid:
        mov     cp,ax
        lea     bx,cp

        farPtr  pcpid,ss,bx
        farPtr  pmapcp,ss,npOffsets

        cCall   Force_Valid_CP,<pcpid,pmapcp>

;/*
;** !!! Call WinSetErrInfo when Force_Valid_CP returns a non-zero result.
;*/

        or      ax,ax
        jz      ccp_continue
        mov     ax, ERROR_VIO_BAD_CP
        jmp     err_exit_Check_Code_Page

ccp_continue:

        les     bx,lpVioPS
        test    es:viops_CodepageID[bx],0ffffh
        jz      leave_null_cpid_alone

        mov     ax,cp
        mov     es:viops_CodepageID[bx],ax


leave_null_cpid_alone:

        mov     es,VioSegData
        assumes es,Data

        lds     si,lpVioPS
        assumes ds,nothing

;/*
;** Whenever viops_npmapfontsloaded is zero, we use the code page map
;** defined for the base symbol set.  The choice of the default map is
;** not critical since a null map reference will always be paired with
;** a null font selector, and hence won't cause any drawing. (See the
;** InterpretAttributes routine in CellDraw.asm.)  A valid default is
;** necessary to make sure that the lvb scanning logic (see CellScan.asm)
;** never fails.
;*/

        mov     bx,npOffsets
        mov     ax,ss:[bx]
        mov     ss:[bx+2],ax
        mov     ss:[bx+4],ax
        mov     ss:[bx+6],ax

        mov     cx,viops_npmapfontsloaded[si]
        jcxz    check_lcid_map2

        mov     ss:[bx+2],cx


check_lcid_map2:

        mov     cx,viops_npmapfontsloaded[si][2]
        jcxz    check_lcid_map3

        mov     ss:[bx+4],cx


check_lcid_map3:

        mov     cx,viops_npmapfontsloaded[si][4]
        jcxz    lcid_maps_loaded

        mov     ss:[bx+6],cx


lcid_maps_loaded:


;/*
;** Now we must decide what cell size to use.
;** do this by searching table of cell-sizes. Note that this table is ordered
;** by cell-size, width most-significant.
;*/

        mov     ax,viops_CellImageWidth[si]     ; get requested width...
        mov     dx,viops_CellImageHeight[si]    ; ... and height
        mov     cx,cDevVioCells         ; get count of available sizes
        lea     bx,adDevVioCells        ; get start of table of sizes

        lea     di,pDefVioFont          ; set the default result

next_cellsize:
        cmp     ax,es:cf_width[bx]      ; if requested width less than...
        jb      cellsize_decided        ; ...width from table we're done

        cmp     dx,es:cf_height[bx]     ; if requested height greater than..
        jb      too_high                ; ...height from table the size is...
        mov     di,bx                   ; ...usable, but try to find larger
too_high:
        add     bx,size CellFont        ; point to next entry
        loop    next_cellsize           ; iterate if more to try

cellsize_decided:

        mov     ax,es:cf_height[di]           ; set cell-height in viops...
        mov     viops_CellImageHeight[si],ax  ; ...to chosen height
        mov     ax,es:cf_width[di]            ; set cell-width in viops...
        mov     viops_CellImageWidth[si],ax   ; ...to chosen width
        mov     ax,es:cf_ptr[di].sel          ; get selector of font defn.

        mov     bx,npSelectors
        mov     ss:[bx],ax

;/*
;** The selectors will be zero unless the corresponding viops_selfontsloaded
;** value is non-zero and corresponds to a font whose cell shape matches that
;** selected above.
;*/

        xor     ax,ax
        mov     ss:[bx+2],ax
        mov     ss:[bx+4],ax
        mov     ss:[bx+6],ax
        mov     ax,viops_CellImageWidth[si]
        mov     dx,viops_CellImageHeight[si]


        mov     cx,viops_selfontsloaded[si]
        jcxz    check_font2

        mov     es,cx
        assumes es,FontSeg

        cmp     ax,fsDef.fdCellWidth
        jne     check_font2

        cmp     dx,fsDef.fdCellHeight
        jne     check_font2

        mov     ss:[bx+2],cx


check_font2:

        mov     cx,viops_selfontsloaded[si][2]
        jcxz    check_font3

        mov     es,cx
        assumes es,FontSeg

        cmp     ax,fsDef.fdCellWidth
        jne     check_font3

        cmp     dx,fsDef.fdCellHeight
        jne     check_font3

        mov     ss:[bx+4],cx


check_font3:

        mov     cx,viops_selfontsloaded[si][4]
        jcxz    font_selectors_loaded

        mov     es,cx
        assumes es,FontSeg

        cmp     ax,fsDef.fdCellWidth
        jne     font_selectors_loaded

        cmp     dx,fsDef.fdCellHeight
        jne     font_selectors_loaded

        mov     ss:[bx+6],cx


font_selectors_loaded:

;/*
;** If the cell height has changed since the last call, adjust the
;** cursor start/end lines to match the new cell size.
;*/

        cmp     dx,viops_CellHeightLatch[si]
        je      exit_Check_Code_Page

        mov     viops_CellHeightLatch[si],dx
        dec     dx
        cmp     viops_TextCursorStartLine[si],dx
        jbe     check_height_next
        mov     viops_TextCursorStartLine[si],dx
check_height_next:
        cmp     viops_TextCursorEndLine[si],dx
        jbe     check_height_done
        mov     viops_TextCursorEndLine[si],dx
check_height_done:

exit_Check_Code_Page:
        xor     ax,ax

err_exit_Check_Code_Page:

cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = ScrollRect
;*
;* DESCRIPTION   =
;*
;*    This routine implements the ScrollRect call by falling into CharRect to
;*    redraw the rectangle which has been scrolled in the LVB.  Other device
;*    drivers may wish to split this work into two parts -- a screen-to-screen
;*    bitblt and a CharRect call to draw the tail region invalidated by
;*    the scrolling operation.  On the EGA that's slower than just redrawing
;*    the entire rectangle.  EGA memory is S-l-o-o-o-w!
;*
;* INPUT         =
;*
;*     hdc                       hdc;          -- A DC handle.
;*     VioPresentationSpace FAR *lpPS;         -- The (A)Vio PS for the console.
;*     ScrollRectRef        FAR *lpScrollDesc; -- The rectangle being scrolled.
;*     HDDI                      hddi          -- DDI handle for the hdc.
;*     LONG                      FunN;         -- Index for the desired function.
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

        check   ScrollRect,<hdc,pviops,pScrollRect,hddc,ulFunN>

labelFP <PUBLIC,ScrollRect>
        errn$   CharRect

;/***************************************************************************
;*
;* FUNCTION NAME = CharRect
;*
;* DESCRIPTION   =
;*
;*     This routine displays a rectangle of character images in a VIO window
;*     according to the state of its presentation space and the cell rectangle
;*     defined by *lpRectDesc.  Its result will be zero for success, and
;*     an error code if a problem is detected.
;*
;*     Warnings: This code assumes the OrgRow and OrgCol fields in a
;*               presentation space are never negative.  VIO and the
;*               Shield Layer must enforce that discipline.
;*
;* INPUT         =
;*
;*     hdc                       hdc;        -- A DC handle.
;*     VioPresentationSpace FAR *lpPS;       -- The (A)Vio PS for the console.
;*     GridRectRef          FAR *lpRectDesc; -- The rectangle to draw.
;*     HDDI                      hddi        -- DDI handle for the hdc.
;*     LONG                      FunN;       -- Index for the desired function.
;*                                           -- (Presumably CharRect)
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   CharRect,<hdc,pviops,pCharRect,hddc,ulFunN>

define_CharRect_frame CharRect

cBegin

        mov     ds,VioSegData
        assumes ds,Data
        mov     dx,hddc.lo
        call    far_enter_driver
        mov     ax,CE_INVALID_PRESENTATION_SPACE        ; assume error
        cwd
        njc     cr_exit_no_lock

;/*
;** We save the current frame pointer in the bottom of the stack segment
;** to allow BP be used as a work register in some of the scanning and
;** drawing routines.
;*/

        mov     ss:[cb_BPSaveSlot],bp


;/*
;** I call Check_Code_Page to coerce the CodepageID, CellImageHeight, and
;** CellImageWidth fields of the PS to valid and consistent values.  As a
;** side effect it also places the correct values in wSymbolSetSelectors
;** and wSymbolSetOffsets
;*/

        lea     ax,wSymbolSetSelectors
        lea     bx,wSymbolSetOffsets

        cCall   Check_Code_Page,<lpPS,ax,bx>

        or      ax,ax
        jz      cr_continue
        jmp     NoDisplayWork

cr_continue:

        mov     ax,wSymbolSetOffsets
        mov     npcpmap,ax

        lds     si,lpPS                 ; Start looking at the
        assumes ds,nothing              ; Presentation Space.

        mov     ax,viops_CellImageHeight[si]
        mov     wCellHeight,ax
        mov     ax,viops_CellImageWidth[si]
        mov     wCellWidth,ax

        mov     ds,VioSegData                           ; Restore our Data segment.
        assumes ds,Data

;/*
;** Here we examine the supplied ddc to see if it is a display device
;** (DDC_DEVICE) or something else.  We can draw with a display device
;** that is visible (DDC_VISIBLE), but not with a memory bitmap.
;*/

        mov     si,hddc.lo              ; Do we have a display device?

;/*
;** check COM_DRAW bit
;*/
        mov     cl,[si].ddc_fb
        test    cl,DDC_DEVICE
        jz      Not_A_Display_Device2
        and     cx,DDC_VISIBLE
        jz      bounds_only

        and     cx,FunN.hi              ; FunN - MSW is commands
        jnz     Got_A_Display_Device2   ; skip draw
        .errnz  COM_DRAW-DDC_VISIBLE

Not_A_Display_Device2:

        jmp     Drawing_Deferred

bounds_only:

;/*
;** We won't be drawing anything this time.  Note however that we still
;** must go through the coordinate transforms to calculate the bounds
;** rectangle.  The boolean variable fDontDraw indicates whether we'll
;** draw or not.
;*/

        mov     fDontDraw,1
        jmp     SHORT setup_for_drawing

Got_A_Display_Device2:
        cmp     fGrimReaper,0           ; Skip draw if dead
        jnz     Not_A_Display_Device2

        mov     fDontDraw,0

setup_for_drawing:

        mov     bx,[si].ddc_npsd        ; DS:BX -> surface

        mov     ax,[bx].sd_pBits.sel    ; Copy far pointer to bits
        mov     seg_lpBitmapBits,ax
        mov     ax,[bx].sd_pBits.off
        mov     off_lpBitmapBits,ax

        mov     ax,[bx].sd_cx
        mov     wDestWidth,ax
        mov     ax,[bx].sd_cy
        mov     wDestHeight,ax

        mov     ax,[bx].sd_cbScan       ; Copy the width of the bit
        mov     wDestBMWidth,ax         ; array in bytes.

        lds     si,lpPS                 ; Resume our scan of the
                                        ; Presentation Space.

        mov     ax,viops_BufferRowCount[si]   ; Pick up the dimensions
        mov     wRowCount,ax            ; of the logical video
        mov     ax,viops_BufferColumnCount[si]; buffer.
        mov     wColCount,ax

        mov     cx,viops_CellByteSize[si]     ; Get the size of a buffer cell.
        mov     wCellSize,cx

        ShiftRight  cx,1                ; Compute the shift factor
        mov     wCellSizeShift,cx       ; corresponding to the cell size.
                                        ; NB:  This particular trick works
                                        ;      only for sizes 2 (Vio) and
                                        ;      4 (AVio).

        shl     ax,cl                   ; Calculate the width in bytes
        mov     wLVBRowBytes,ax         ; of an LVB row.

        mov     ax,viops_Sel_LogicalVideoBuffer[si]
        mov     seg_LVB,ax

        test    fDontDraw,0ffffh
        jz      drawing_permitted
        xor     ax,ax
        jmp     SHORT Skip_Exclusion

drawing_permitted:

;/*
;** Certain flags in the rgfShieldStates field cause drawing actions to be
;** deferred.  Here we examine those flags.
;*/

        mov     ax,viops_rgfShieldStates[si]
        test    ax,fServeNobody
        jnz     Drawing_Deferred

        and     ax,(fShieldCalling OR fServeShieldOnly)
        cmp     ax,fServeShieldOnly
        jne     Drawing_Allowed

Drawing_Deferred:

        xor     ax,ax
        jmp     NoDisplayWork

Drawing_Allowed:

;/*
;** Here we exclude the text cursor from the screen if it is visible and lies
;*/

        xor     ax,ax

        test    viops_rgfShieldStates[si],fCursorShowing
        jz      Skip_Exclusion

        les     di,lpRectDesc
        mov     cx,viops_CursorRow[si]
        mov     bx,es:WORD PTR cellrect_StartRow[di]
        cmp     cx,bx
        jl      Skip_Exclusion

        sub     cx,bx
        cmp     cx,es:WORD PTR cellrect_RectDepth[di]
        jge     Skip_Exclusion

        mov     cx,viops_CursorCol[si]
        mov     bx,es:WORD PTR cellrect_StartColumn[di]
        cmp     cx,bx
        jl      Skip_Exclusion

        sub     cx,bx
        cmp     cx,es:WORD PTR cellrect_RectWidth[di]
        jge     Skip_Exclusion


;/*
;** The text cursor lies within the rectangle we're to draw.
;** No need to actually remove the cursor from that rectangle,
;** since all we need do is redraw the cursor after we're finished
;** drawing.  Our drawing actions will obliterate the cursor anyway.
;*/

ifdef HW_BLT

        lds     si,lpPS
        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        mov     ds,VioSegData
        assumes ds,Data
        arg     <hdc,(hddc.lo),(FunN.hi),lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertSplitCursor,<lpPS>

endif;HW_BLT

        mov     ax,1

Skip_Exclusion:

        mov     fExcluding,ax


;/*
;** The following code calculates the pixel origin of the screen relative to
;** the image of the full logical video buffer.
;*/

;/*
;** First we calculate the height of the client rect in pixels.
;*/

        lds     si,lpPS

        mov     ax,viops_WindowHeight[si]
        mul     wCellHeight
        mov     bx,ax

;/*
;** Then we retrieve the screen coordinates for the bottom left corner
;** of the client rectangle.
;*/

        mov     es,VioSegData
        assumes es,Data
        push    di
        mov     di,hddc.lo
        les     di,es:[di].ddc_prddc
        assumes es,nothing
        mov     dx,es:[di].rddc_ptsOrg.pts_x
        mov     al,viops_PartialCellAdjust[si]
        cbw
        add     ax,es:[di].rddc_ptsOrg.pts_y
        and     dx,(not 7)              ; In case the left window edge is
        pop     di                      ; not aligned on a byte boundary.
        fw_zero <es>
        assumes es,nothing

;/*
;** Now DX/AX hold the X/Y coords of the bottom left corner of the window
;** client rectangle.
;*/

;/*
;** We transform the coordinates to have their origin at the top left
;** corner of the screen.
;*/

;/*
;** First we map  DX/AX to the top left corner of the window.
;*/

        add     ax,bx

;/*
;** Then adjust those coordinates to be relative to the top left corner of
;** the screen.
;*/

        mov     bx,wDestHeight
        sub     bx,ax                   ; ptClientOrigin.ycoord
        mov     cx,dx                   ; ptClientOrigin.xcoord

;/*
;** Now the Window Origin coordinates define the LVB cell drawn at the
;** bottom left corner of the window.  Also, those coordinates are relative
;** to the bottom left corner of the LVB.  To avoid changing lots of code
;** we map those coordinates so they refer to the cell which is drawn in
;** the top left corner of the window and we transform the coordinates to
;** be relative to the top left corner of the LVB.
;*/


        mov     ax,wRowCount            ; Transform to top left origin.
        sub     ax,viops_WindowOriginRow[si]

        sub     ax,viops_WindowHeight[si]     ; Map to the top left corner of
                                        ; the window image.

        mul     wCellHeight             ; Map relative to TL of screen.
        sub     ax,bx
        mov     wVertLineOffset,ax

        mov     ax,viops_WindowOriginColumn[si]
        ColToPix    ax
        sub     ax,cx
        mov     wHorzPixelOffset,ax
        PixToCol    ax
        mov     wDestColOffset,ax


;/*
;**;;;;;;;; Examine the rectangle descriptor ;;;;;;;;;;;;;;;;;;;;;;;;;;;
;*/

;/*
;** This code clips the the rectangle descriptor to lie within the LVB and
;** maps it into a RECT descriptor relative to screen coordinates.  This
;** is necessary because the Vis Region clipping below only bounds the work
;** to within the window client region.  The Shield Layer code will guarantee
;** that the window's client rect won't extend beyond the image of the LVB.
;** No such assumptions can be made for AVio support, however.  Thus the
;** need for the clipping action.
;**
;** Side Issue: AVio code which lets the client region get larger than the
;**             LVB image or which doesn't exercise discipline wrt the
;**             window origin will have to define a border color and
;**             paint the border region itself.
;*/

        lea     di,drBounds                 ; Clear the Bounds rectangle
        mov     ax,ss                       ; to all zeroes.
        mov     es,ax
        xor     ax,ax                       ;!!! You are assuming that these
        cld                                 ;!!! will all be positive.  That
        mov     cx,(size RECTL)/2           ;!!! seems       to me.
        rep     stosw                       ;!!! ..walt

        mov     di,wDestHeight              ; So we can flip the coords
                                            ; to have the origin at the
                                            ; bottom left.

        lds     si,lpRectDesc

;/*
;** Here we're going to constrain the passed rectangle to lie within the
;** logical video buffer.  That is, cellrect_StartRow is coerced to the range
;** [0..wRowCount-1] and cellrect_RectDepth is coerced to the range
;** [0..wRowCount-cellrect_StartRow].
;*/

        xor     ax,ax

;/*
;** Given DCR 799 cellrect_StartRow will define the bottom left cell of a rectangle
;** to be displayed, and it will be relative to the bottom left corner of
;** the logical video buffer.  For now we map and transform that coordinate
;** so that it denotes the top left cell of that rectangle and is relative
;** to the top left corner of the LVB.
;*/

        mov     bx,wRowCount                ; BL => TL origin.

        sub     bx,WORD PTR cellrect_StartRow[si]   ; Map to TL corner of the
        sub     bx,WORD PTR cellrect_RectDepth[si]  ; rectangle.

        SMax    bx
        mov     cx,WORD PTR cellrect_RectDepth[si]
        sub     cx,ax
        mov     ax,wRowCount
        sub     ax,bx
        SMin    cx
        jg      VerticalMapping
        jmp     NoDisplayWork


VerticalMapping:

        mov     ax,bx                   ; Map the vertical bounds of
        mul     wCellHeight             ; the cell rectangle to the
        xchg    cx,ax                   ; image rectangle.
        mul     wCellHeight
        sub     cx,wVertLineOffset
        mov     dx,di
        sub     dx,cx
        mov     drBounds.rcl_yTop.lo,dx ;word ptr rect_y2 ... Top ...
        add     dx,dx                   ;!!! kludge by walt
        sbb     dx,dx                   ;!!! kludge by walt
        mov     drBounds.rcl_yTop.hi,dx ;!!! kludge by walt
        add     ax,cx
        mov     dx,di
        sub     dx,ax
        mov     drBounds.rcl_yBottom.lo,dx ;rect_y1 ... Bottom ...
        xchg    ax,dx                      ;!!! kludge by walt
        cwd                                ;!!! kludge by walt
        xchg    ax,dx                      ;!!! kludge by walt
        mov     drBounds.rcl_yBottom.hi,ax ;!!! kludge by walt


;/*
;** Here we coerce cellrect_StartColumn and cellrect_RectWidth so that cellrect_StartColumn is in the range
;** [0..wRowCount-1] and cellrect_RectWidth is in to the range [0..wColCount-cellrect_StartColumn].
;*/

        xor     ax,ax                           ; Constrain the cell rectangle
        mov     bx,WORD PTR cellrect_StartColumn[si]       ; horizontally to lie within
        SMax    bx                              ; the LVB.
        mov     cx,WORD PTR cellrect_RectWidth[si]
        sub     cx,ax
        mov     ax,wColCount
        sub     ax,bx
        SMin    cx
        jg      HorizontalMapping
        jmp     NoDisplayWork


HorizontalMapping:

        mov     ax,bx                             ; ColToPix uses "mul ax"
        ColToPix    ax                  ; Map the horizontal bounds of
        sub     ax,wHorzPixelOffset     ; the cell rectangle to the
                                        ; image rectangle.

        mov     drBounds.rcl_xLeft.lo,ax    ; WORD PTR rect_x1... Left ...
        cwd                                           ; !!! is this still a kludge Walt?
        mov     drBounds.rcl_xLeft.hi,dx    ; !!! is this still a kludge Walt?

        xchg    ax,cx
        ColToPix    ax
        add     ax,cx
        mov     drBounds.rcl_xRight.lo,ax   ;WORD PTR rect_x2 ... Right ...
        cwd
        mov     drBounds.rcl_xRight.hi,dx


;/*
;** When we reach this point the image rectangle (drBounds) has been
;** calculated and clipped to lie within the image of the LVB.
;*/

        mov     ds,VioSegData
        mov     di,FunN.hi
        test    di,(COM_BOUND+COM_ALT_BOUND)
        jz      dont_accumulate_charrect_bounds

        mov     si,hddc.lo
        mov     ax,drBounds.rcl_xLeft.lo
        mov     cx,drBounds.rcl_xRight.lo
        mov     bx,drBounds.rcl_yBottom.lo
        mov     dx,drBounds.rcl_yTop.lo
        dec     dx                          ; To make the rect inclusive
        dec     cx

        cCall   far_InnerAccumulateBounds

dont_accumulate_charrect_bounds:

        test    fDontDraw,0ffffh
        jz      draw_the_char_rect

        xor     ax,ax
        jmp     SHORT NoDisplayWork

draw_the_char_rect:

;/*
;** We set up fSomethingDrawn to detect whether we have a null
;** visible region.  If so, the Winthorn screen group may not be active.
;*/

        xor     ax,ax
        mov     fSomethingDrawn,ax

;/*
;** Now we call enumerate_clip_rects to drive the DrawImageRect routine.
;*/

        lea     bx,drBounds
        regPtr  lpdrBounds,ss,bx

        mov     si,bp                   ; To make our stack frame
                                        ; available.

        mov     cx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        cCall   far_enumerate_clip_rects,<off_hddc,lpdrBounds,CodeOFFSET DrawImageRect>

        xor     ax,ax

;/*
;** If nothing was drawn, don't do anything to the ega registers.  That's
;** because the Winthorn screen group may be in the background.
;*/

        test    fSomethingDrawn,0FFFFh
        jz      null_visible_region

        push    ax
        call    SetDisplayDefaults      ; Revert to the default states assumed
                                        ; by the rest of the driver code.
        test    fExcluding,0FFFFh
        jz      Cursor_Wasnt_Excluded

        lds     si,lpPS

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        mov     ds,VioSegData
        assumes ds,Data
        arg     <hdc,(hddc.lo),(FunN.hi),lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertSplitCursor,<lpPS>

Cursor_Wasnt_Excluded:

        pop     ax

NoDisplayWork:
null_visible_region:

        xor     dx,dx               ; Because our result is ULONG ?!?

        mov     ds,VioSegData
        assumes ds,Data
        call    far_leave_driver
cr_exit_no_lock:

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = CharStr
;*
;* DESCRIPTION   = This routines calls CharRectGlue as necessary to accomplish the
;*                 work defined by the lpStringDesc descriptor.
;*
;* INPUT         =
;*
;*     hdc                       hdc;          -- A DC handle
;*     VioPresentationSpace FAR *lpPS;         -- The  VioPS for the console
;*     GridStringRef        FAR *lpStringDesc; -- The string to draw
;*     HDDI                      hddi          -- DDI handle for the hdc.
;*     LONG                      FunN;         -- Index for the desired function.
;*                                             -- (Presumably CharStr)
;*
;* OUTPUT        = As specified for the GreCharStr function.
;*
;* RETURN-NORMAL = As specified for the GreCharStr function.
;* RETURN-ERROR  = As specified for the GreCharStr function.
;*
;**************************************************************************/

        check   CharStr,<hdc,pviops,pCharStr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing


cProc   CharStr,<PUBLIC,FAR,NODATA>,<si,di>

        parmD   hdc                     ; A long pointer to the display
                                        ; context we'll be using.
        parmD   lpPS
        parmD   lpStrDesc
        parmD   hddc
        parmD   FunN                    ; Index for the desired driver
                                        ; function (presumably CharStr).

        localW  wLVBRows                ; Dimensions of the LVB
        localW  wLVBCols

        localW  wCellCount              ; Length of the cell string

        localV  SubRect,<size GridRectRef>  ; Subrectangle passed to CharRectangle.

cBegin

        mov     ds,VioSegData
        assumes ds,Data
        mov     dx,hddc.lo
        call    far_enter_driver
        mov     ax,CE_INVALID_PRESENTATION_SPACE        ; assume error
        cwd
        njc     cs_exit_no_lock

        mov     ax,ss                   ; Zero out SubRect.
        mov     es,ax
        lea     di,SubRect
        xor     ax,ax
        mov     cx,(SIZE GridRectRef)/2
        cld
        rep     stosw

        lds     si,lpPS

        mov     bx,viops_BufferRowCount[si]
        mov     wLVBRows,bx
        mov     cx,viops_BufferColumnCount[si]
        mov     wLVBCols,cx

        lds     si,lpStrDesc

        mov     ax,WORD PTR cellstr_StartRow[si]
        cmp     ax,bx
        jb      CS_Row_Inx_OK

        mov     ds,VioSegData
        mov     ax,GRE_INVALIDROWINDEX
        jmp     CharStr_Error_Exit


CS_Row_Inx_OK:

        mov     WORD PTR SubRect.cellrect_StartRow,ax

        mov     bx,WORD PTR cellstr_StartColumn[si]
        cmp     bx,cx
        jb      CS_Col_Inx_OK

        mov     ds,VioSegData
        mov     ax,GRE_INVALIDCOLUMNINDEX
        jmp     CharStr_Error_Exit


CS_Col_Inx_OK:

        mov     WORD PTR SubRect.cellrect_StartColumn,bx

        mov     cx,WORD PTR cellstr_StringLength[si]
        mov     wCellCount,cx

        mov     ds,VioSegData                       ; Restore DS for CharRectangle

;/*
;** The Code below partitions the designated string into three parts:
;**
;**   1.  A trailing string in the first row affected.
;**   2.  A sequence of middle rows which are also affected.
;**   3.  A leading string in the last row to be affected.
;**
;** In any particular call, some of these partitions may be empty.
;**
;** The common situation of having a string which fits completely in a
;** single row is handle as either a case 1 partition or a case 2 partition.
;*/

        or      cx,cx                   ; Check for zero or negative
        jns     Non_Negative_CS_Length

        mov     ax,GRE_NEGATIVELENGTH
        jmp     CharStr_Error_Exit


Non_Negative_CS_Length:

        jg      Non_Empty_String        ; string length.
CharStr_Done_Relay:
        jmp     CharStr_Done


Non_Empty_String:

        or      bx,bx                   ; If the string does not begin at
        jnz     CS_FirstRow             ; column zero, partition 1 is
                                        ; non-empty.

        cmp     cx,wLVBCols             ; Ditto if the length is less than
        jge     CS_Middle               ; a full row.


CS_FirstRow:

;/*
;** This code handles partition 1.
;*/

        mov     ax,1
        mov     WORD PTR SubRect.cellrect_RectDepth,ax

        mov     ax,wLVBCols             ; Width <- StringLength
        sub     ax,bx                   ;          Min RowLength - ColOffset
        SMin    cx                      ; 
        mov     WORD PTR SubRect.cellrect_RectWidth,cx

        sub     wCellCount,cx

        lea     bx,SubRect
        farPtr  pSubRect,ss,bx
        cCall   CharRect,<hdc,lpPS,pSubRect,hddc,FunN>

        or      ax,ax
        jz      CS_Part1_Done_OK
        jmp     CharStr_Error_Exit


CS_Part1_Done_OK:

        mov     cx,wCellCount           ; Are we done?
        jcxz    CharStr_Done_Relay

                                        ; If not, adjust the rectangle
                                        ; descriptor to start in column 0 of
                                        ; the next row.

        dec     WORD PTR SubRect.cellrect_StartRow
        xor     ax,ax
        mov     WORD PTR SubRect.cellrect_StartColumn,ax

        cmp     cx,wLVBCols             ; Do we have at least a full row
        jl      CS_LastRow              ; left?


CS_Middle:

;/*
;** This code handles partition 2.
;*/

        mov     ax,cx
        xor     dx,dx
        mov     bx,wLVBCols
        div     bx
        mov     WORD PTR SubRect.cellrect_RectDepth,ax
        mov     WORD PTR SubRect.cellrect_RectWidth,bx
        mul     bx
        sub     cx,ax
        mov     wCellCount,cx

        mov     ax,WORD PTR SubRect.cellrect_StartRow   ; Map cellrect_StartRow to the
        sub     ax,WORD PTR SubRect.cellrect_RectDepth  ; bottom left corner of
        inc     ax                              ; the rectangle to be shown.
        mov     WORD PTR SubRect.cellrect_StartRow,ax

        lea     bx,SubRect
        farPtr  pSubRect,ss,bx
        cCall   CharRect,<hdc,lpPS,pSubRect,hddc,FunN>

        or      ax,ax
        jz      CS_Part2_Done_OK
        jmp     CharStr_Error_Exit

CS_Part2_Done_OK:
        mov     cx,wCellCount           ; Are we done?
        jcxz    CharStr_Done
                                        ; If not, move StartRow down one
                                        ; row to set up for partition 2.

        dec     WORD PTR SubRect.cellrect_StartRow

CS_LastRow:

;/*
;** This code handles partition 3.
;*/

        mov     WORD PTR SubRect.cellrect_RectWidth,cx
        mov     ax,1
        mov     WORD PTR SubRect.cellrect_RectDepth,ax

        lea     bx,SubRect
        farPtr  pSubRect,ss,bx
        cCall   CharRect,<hdc,lpPS,pSubRect,hddc,FunN>

        or      ax,ax
        jnz     CharStr_Error_Exit

        errn$   CharStr_Done


CharStr_Done:

        xor     ax,ax

CharStr_Error_Exit:

        xor     dx,dx               ; Because our result is ULONG ?!?

        call    far_leave_driver
cs_exit_no_lock:

cEnd



        assumes ds,nothing
        assumes es,nothing



;/***************************************************************************
;*
;* FUNCTION NAME = InvertSplitCursor
;*
;* DESCRIPTION   =
;*
;*          This routine inverts the text cursor based on the information in the
;*          private portion of the PS structure (hVioWindow .. rgfShieldStates).
;*
;*          It detects split cursors (StartLine > EndLine) and breaks them into two
;*          inversion actions.  For splits, we assume that XLatch, YLatch,
;*          WidthLatch, and HeightLatch correspond to the complete vertical extent
;*          of a cell.  The latched StartLine and EndLine values are used to split
;*          that rectangle into the two inversion regions and the middle unchanged
;*          region.
;*
;*          For solid cursors XLatch, YLatch, WidthLatch, and HeightLatch directly
;*          define the image region to invert.
;*
;* INPUT         = hdc       hdc;
;*                 WORD      pDDC;
;*                 BOOL      afFunN;
;*                 WORD FAR *lpBitmapBits;
;*                 WORD      wDestHeight,
;*                           wDestBMWidth;
;*                 VioPresentationSpace FAR * pAVioPS;
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        cProc   InvertSplitCursor,<PUBLIC,NEAR>,<bx,cx,dx,si,di,ds,es>

        parmD   hdc
        parmW   pDDC
        parmW   afFunN
        parmD   lpBitmapBits
        parmW   wDestHeight
        parmW   wDestBMWidth
        parmD   pAVioPS

        localW  wXCoord
        localW  wYCoord
        localW  wHeight
        localW  wWidth
        localW  wOrigin_Correction

        cBegin

        lds     si,pAVioPS
        mov     al,viops_PartialCellAdjust[si]
        cbw
        mov     wOrigin_Correction,ax
        mov     ax,viops_CursorStartLine[si]
        cmp     ax,viops_CursorEndLine[si]
        jbe     solid_cursor


split_cursor:

;/*
;** First we invert the bottom half of the split.  That is, the
;** rectangle from StartLine to the bottom of the current cell.
;*/

        mov     cx,viops_CellHeightLatch[si]
        sub     cx,ax
        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        add     bx,wOrigin_Correction
        mov     dx,viops_WidthLatch[si]
        arg     <hdc,pDDC,afFunN,lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertTextCursor,<ax,bx,cx,dx>

;/*
;** Then we invert the top part of the split.  That is, from the top of
;** the cell to EndLine.
;*/

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        add     bx,wOrigin_Correction
        add     bx,viops_CellHeightLatch[si]
        mov     cx,viops_CursorEndLine[si]
        inc     cx
        sub     bx,cx
        mov     dx,viops_WidthLatch[si]
        arg     <hdc,pDDC,afFunN,lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertTextCursor,<ax,bx,cx,dx>

        jmp     SHORT exit_InvertSplitCursor


solid_cursor:

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        add     bx,wOrigin_Correction
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        arg     <hdc,pDDC,afFunN,lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertTextCursor,<ax,bx,cx,dx>

        errn$   exit_InvertSplitCursor

exit_InvertSplitCursor:

        cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = InvertTextCursor
;*
;* DESCRIPTION   = Inverts a rectangle within the client rectangle to show or hide
;*                 the cursor.
;*
;* INPUT         = hdc       hdc;
;*                 WORD      pDDC;
;*                 WORD FAR *lpBitmapBits;
;*                 WORD      wDestHeight,
;*                           wDestBMWidth,
;*                           wXCoord,
;*                           wYCoord,
;*                           wHeight,
;*                           wWidth;
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

define_Invert_Cursor_Frame InvertTextCursor

cBegin

        xor     ax,ax
        mov     fSomethingDrawn,ax

;/*
;** Find the bottom left corner
;*/

        mov     ds,VioSegData
        assumes ds,Data

        mov     si,pDDC
        les     si,[si].ddc_prddc
        assumes es,nothing
        mov     dx,es:[si].rddc_ptsOrg.pts_x
        mov     ax,es:[si].rddc_ptsOrg.pts_y
        and     dx,(not 7)              ; In case the left window edge is
                                        ; not aligned on a byte boundary.

;/*
;** Now DX/AX contain the X/Y screen coordinates of our window origin.
;** We can map the coordinate parameters to the screen:
;*/

        mov     si,dx                   ; Because the CWD instruction
                                        ; below destroys DX...
        add     ax,wYCoord
        add     si,wXCoord
        mov     bx,wHeight
        mov     cx,wWidth
        add     bx,ax
        add     cx,si

;/*
;** Now we'll build up the RECTL parameter for use with
;** enumerate_clip_rects.
;*/

        cwd
        mov     drBounds.rcl_yBottom.lo,ax
        mov     drBounds.rcl_yBottom.hi,dx
        mov     ax,si
        cwd
        mov     drBounds.rcl_xLeft.lo,ax
        mov     drBounds.rcl_xLeft.hi,dx
        mov     ax,bx
        cwd
        mov     drBounds.rcl_yTop.lo,ax
        mov     drBounds.rcl_yTop.hi,dx
        mov     ax,cx
        cwd
        mov     drBounds.rcl_xRight.lo,ax
        mov     drBounds.rcl_xRight.hi,dx

;/*
;** If either of the BOUNDs flags is set, we must
;** accumulate bounds information for this drawing
;** action.
;*/

        mov     di,afFunN
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      dont_accumulate_text_cursor_bounds

        mov     si,pDDC
        mov     ax,drBounds.rcl_xLeft.lo
        mov     cx,drBounds.rcl_xRight.lo
        mov     bx,drBounds.rcl_yBottom.lo
        mov     dx,drBounds.rcl_yTop.lo
        dec     dx                          ; To make the rect inclusive
        dec     cx

        cCall   far_InnerAccumulateBounds

dont_accumulate_text_cursor_bounds:

;/*
;** we can draw if the display device is visible or COM_DRAW bit is on
;** otherwise only do the bounds accumulation.
;*/

        test    afFunN,COM_DRAW
        jz      exit_InvertTextCursor

        lea     bx,drBounds

        regPtr  lpInvertRect,ss,bx

;/*
;** Since enumerate_clip_rects will pass my SI and DI register values
;** along to InvertClippedRect, I use SI to pass access to my stack
;** frame.
;*/

        mov     si,bp

        mov     cx,RECTDIR_LFRT_BOTTOP-1 ;Favored direction
        cCall   far_enumerate_clip_rects,<pDDC,lpInvertRect,CodeOFFSET InvertClippedRect>

;/*
;** If nothing was drawn we don't reset the display state.  That's not
;** just polite.  It's necessary to prevent interfering with full screen
;** screen groups.  When Winthorn is in the background, all the visible
;** regions are set empty, but drawing and device driver actions proceed
;** normally.
;*/

        mov     cx,fSomethingDrawn
        jcxz    exit_InvertTextCursor

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

        call    SetDisplayDefaults


exit_InvertTextCursor:

cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = UpdateCursor
;*
;* DESCRIPTION   = This routine implements the functionality of GreUpdateCursor.
;*                 It adjusts the display as necessary to match the text cursor as
;*                 described in *lpPS.
;*
;* INPUT         =
;*
;*          hdc                       hdc;        -- A DC handle
;*          VioPresentationSpace FAR *lpPS;       -- The (A)Vio PS for the console.
;*          HDDI                      hddi        -- DDI handle for the hdc.
;*          LONG                      FunN;       -- Index for the desired function.
;*                                                -- (Presumably UpdateCursor)
;*           where:
;*               All argument are as specified for the GreUpdateCursor function.
;*
;*           Return values:
;*                    As specified for the GreUpdateCursor function.
;*
;* OUTPUT        =  As specified for the GreUpdateCursor function.
;*
;* RETURN-NORMAL =  As specified for the GreUpdateCursor function.
;* RETURN-ERROR  =  As specified for the GreUpdateCursor function.
;*
;**************************************************************************/

        check   UpdateCursor,<hdc,pviops,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   UpdateCursor,<PUBLIC,FAR,NODATA>,<bx,cx,si,di,ds,es>

        parmD   hdc                     ; Handle for the device context to use.
        parmD   lpPS                    ; Address of the Vio PS to use.
        parmD   hddc                    ; Handle for the Display Device Context
        parmD   FunN                    ; Index for the desired driver
                                        ; function (presumably UpdateCursor).

        localW  wCellHeight
        localW  wCellWidth                                                  ;D2A
        localD  lpBitmapBits
        localW  wDestWidth
        localW  wDestHeight
        localW  wDestBMWidth

        localV  wSymbolSelectors,8      ;!!!CONSTANTS???
        localV  wSymbolOffsets,8

cBegin
        mov     ds,VioSegData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        cCall   far_enter_driver
        mov     ax,CE_INVALID_PRESENTATION_SPACE        ; assume error
        cwd
        njc     uc_exit_no_lock

        ddc?    si


;/*
;** First we call Check_Code_Page to force lpPS->CellImageHeight to a
;** valid value.  wSymbolSelectors and wSymbolOffsets are necessary for
;** the call and irrelevant otherwise.
;*/

        lea     ax,wSymbolSelectors
        lea     bx,wSymbolOffsets

        cCall   Check_Code_Page,<lpPS,ax,bx>

        or      ax,ax
        jz      uc_continue
        jmp     uc_badexit

uc_continue:

;/*
;** To prepare for display work we must retrieve information about
;** where the location of the screen bitmap and its dimensions.
;*/


;/*
;** Here we examine the supplied ddc to see if it is a display device
;** (DDC_DEVICE) or something else.
;*/

        mov     cl,[si].ddc_fb
        test    cl,DDC_DEVICE
        njz     Cursor_Updated
        and     cx,DDC_VISIBLE
        or      cx,NOT COM_DRAW
        and     FunN.hi,cx              ; FunN - MSW is commands

        .errnz  COM_DRAW-DDC_VISIBLE

        cmp     fGrimReaper,0           ; Skip draw if dead
        jz      @F
        and     FunN.hi,NOT COM_DRAW
@@:

        mov     bx,[si].ddc_npsd        ; DS:BX -> surface

        mov     ax,[bx].sd_pBits.sel    ; Copy far pointer to bits
        mov     seg_lpBitmapBits,ax
        mov     ax,[bx].sd_pBits.off
        mov     off_lpBitmapBits,ax

        mov     ax,[bx].sd_cx
        mov     wDestWidth,ax
        mov     ax,[bx].sd_cy
        mov     wDestHeight,ax

        mov     ax,[bx].sd_cbScan       ; Copy the width of the bit
        mov     wDestBMWidth,ax         ; array in bytes.

;/*
;** Now we can examine the state of the text cursor fields in
;** the vio presentation space.
;*/

;/*
;** First we compare the controlling fields of the PS against the
;** snapshot we keep in our private data.
;*/

        lds     si,lpPS
        mov     ax,viops_CellImageHeight[si]
        mov     wCellHeight,ax

        mov     ax,viops_CellImageWidth[si]     ; Store char width for     ;@D2A
        mov     wCellWidth,ax                   ;   ColToPix later on      ;@D2A

;/*
;** Certain flags in the rgfShieldStates field cause drawing actions to be
;** deferred.  Here we examine those flags.
;*/

        mov     ax,viops_rgfShieldStates[si]
        test    ax,fServeNobody
        jz      Check_for_Limited_Service
        jmp     Cursor_Updated


Check_for_Limited_Service:

        and     ax,(fShieldCalling OR fServeShieldOnly)
        cmp     ax,fServeShieldOnly
        jne     Service_Allowed
        jmp     Cursor_Updated


Service_Allowed:

        add     si,viops_WindowOriginRow
        mov     di,viops_RowOrgLatch
        mov     ax,ds
        mov     es,ax
        cld

        mov     cx,(viops_XLatch-viops_RowOrgLatch)/2
        repe    cmpsw

        mov     si,off_lpPS

        jne     Parameters_Changed
        jmp     Parameters_Unchanged


Parameters_Changed:

;/*
;** The parameters have changed.  If the cursor is currently visible we need
;** to hide it.
;*/

        test    viops_rgfShieldStates[si],fCursorShowing
        jz      Examine_Parameters

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        mov     ds,VioSegData

        arg     <hdc,(hddc.lo),(FunN.hi),lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertSplitCursor,<lpPS>

        mov     ds,seg_lpPS

        and     viops_rgfShieldStates[si],NOT fCursorShowing


Examine_Parameters:

;/*
;** Now we have to compute where the cursor will appear given the new
;** set of parameters.  The first step is to copy the parameters to
;** the private data area, filtering them as we go.  We also compute
;** the pixel location of the text cursor.  That information is left
;** in viops_XLatch, viops_YLatch, viops_WidthLatch, and viops_HeightLatch.
;*/

        mov     ax,viops_TextCursorWidth[si]
        or      ax,ax
        jz      Default_Cursor_Width

        cmp     ax,wCellWidth           ; Is cursor same width as font ?   ;@D2C
        je      Cursor_Width_OK         ; If so, then we can leave it      ;@D2C


Default_Cursor_Width:

        mov     ax,wCellWidth           ; Get current font width           ;@D2C
        mov     viops_TextCursorWidth[si],ax ; Store it in CursorWidth     ;@D2C


Cursor_Width_OK:

        mov     viops_CursorWidth[si],al
        mov     viops_WidthLatch[si],ax


        mov     ax,viops_TextCursorEndLine[si]
        cmp     ax,wCellHeight
        jb      End_Line_OK

        mov     ax,wCellHeight
        dec     ax
        mov     viops_TextCursorEndLine[si],ax


End_Line_OK:

        mov     viops_CursorEndLine[si],ax

        mov     bx,viops_TextCursorStartLine[si]
        cmp     bx,wCellHeight
        jb      Start_Line_OK

        mov     bx,wCellHeight
        dec     bx
        mov     viops_TextCursorStartLine[si],bx


Start_Line_OK:

        mov     viops_CursorStartLine[si],bx
        sub     ax,bx
        jns     solid_cursor2

        mov     ax,wCellHeight
        jmp     SHORT save_height

solid_cursor2:

        inc     ax

save_height:

        mov     viops_HeightLatch[si],ax

        mov     ax,viops_TextCursorRow[si]
        cmp     ax,viops_BufferRowCount[si]
        jb      Cursor_Row_OK

        mov     ax,viops_BufferRowCount[si]
        dec     ax
        mov     viops_TextCursorRow[si],ax


Cursor_Row_OK:

        mov     viops_CursorRow[si],ax
        mov     cx,viops_WindowOriginRow[si]
        mov     viops_RowOrgLatch[si],cx
        sub     ax,cx
        inc     ax
        mul     wCellHeight

        mov     bx,viops_CursorEndLine[si]
        cmp     bx,viops_CursorStartLine[si]
        jae     solid_cursor3

        sub     ax,wCellHeight
        jmp     SHORT save_Y_offset


solid_cursor3:

        dec     ax
        sub     ax,bx


save_Y_offset:

        mov     viops_YLatch[si],ax

        mov     ax,viops_TextCursorColumn[si]
        cmp     ax,viops_BufferColumnCount[si]
        jb      Cursor_Col_OK

        mov     ax,viops_BufferColumnCount[si]
        dec     ax
        mov     viops_TextCursorColumn[si],ax


Cursor_Col_OK:

        mov     viops_CursorCol[si],ax
        mov     cx,viops_WindowOriginColumn[si]
        mov     viops_ColOrgLatch[si],cx
        sub     ax,cx

        ColToPix    ax

        mov     viops_XLatch[si],ax


Parameters_Unchanged:

;/*
;** When we get here the viops_XLatch, viops_YLatch, viops_WidthLatch, and viops_HeightLatch
;** fields are synchronized with the public cursor state fields.  Now we
;** must decide whether the cursor should be visible.  It must be visible
;** if
;**
;**       -- This window has the input focus
;**       -- the TextCursorVisible flag is non-zero
;**  and
;**       -- the fCursorIsOn flag is on.
;**
;** Otherwise it should not be visible.
;*/

        mov     ax,viops_rgfShieldStates[si]
        test    ax,fHasTheFocus
        jz      Hide_The_Cursor

        mov     bx,viops_TextCursorVisible[si]
        or      bx,bx
        jz      Hide_The_Cursor

        test    ax,fCursorIsOn
        jz      Hide_The_Cursor

        test    ax,fCursorShowing
        jnz     Cursor_Updated

        or      viops_rgfShieldStates[si],fCursorShowing

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        mov     ds,VioSegData

        arg     <hdc,(hddc.lo),(FunN.hi),lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertSplitCursor,<lpPS>

        jmp     Cursor_Updated


Hide_The_Cursor:

        test    ax,fCursorShowing
        jz      Cursor_Updated

        and     viops_rgfShieldStates[si],NOT fCursorShowing

        mov     ax,viops_XLatch[si]
        mov     bx,viops_YLatch[si]
        mov     cx,viops_HeightLatch[si]
        mov     dx,viops_WidthLatch[si]
        mov     ds,VioSegData

        arg     <hdc,(hddc.lo),(FunN.hi),lpBitmapBits,wDestHeight,wDestBMWidth>

        cCall   InvertSplitCursor,<lpPS>

        errn$   Cursor_Updated

Cursor_Updated:
        xor     ax,ax

uc_badexit:
        mov     ds,VioSegData
        mov     si,off_hddc

        cCall   far_leave_driver

        xor     dx,dx               ; Because our result is ULONG ?!?
uc_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSetAVIOFont
;*
;* DESCRIPTION   =
;*       This routine binds a loaded font to one of the extended LCID's for an
;*       AVIO presentation space (1..3).  The font to be loaded must be fixed
;*       pitch and must match the cell width and height requirements of the the
;*       current device.  Its result will be TRUE if the binding was successfully
;*       constructed and FALSE otherwise.
;*
;*      Side Effects: A successful binding will involve altering entries in the
;*                   VioPresentationSpace32.viops_selFontsLoaded and
;*                   VioPresentationSpace32.viops_npMapFontsLoaded arrays of the
;*                   AVio presentation space corresponding to hdc.
;*
;*      Warnings: If lpFattr is NULL the default codepage of the font is used.
;*
;* INPUT         = hdc     hdc;
;*                 LONG    lpFattr;
;*                 ULONG   FontDef;
;*                 ULONG   inxLCID;
;*                 HDDC    hddc;
;*                 ULONG   inxFn;
;*
;*                 where:
;*                    All arguments are as specified for the
;*                    GreDeviceSetAVIOFont function
;*
;* OUTPUT        = As specified for the GreDeviceSetAVIOFont function.
;*
;* RETURN-NORMAL = As specified for the GreDeviceSetAVIOFont function.
;* RETURN-ERROR  = As specified for the GreDeviceSetAVIOFont function.
;*
;**************************************************************************/

staticD ring3_GetPSAddress,ring3_VioGetPSAddress

cProc   DeviceSetAVIOFont2,<PUBLIC,FAR,NODATA>,<si>
        parmD   hdc
        parmD   pFattr
        parmD   FontDef
        parmD   inxLCID
        parmD   hDDC
        parmD   inxFn

        localD  lpAVioPS
        localW  cp
        localW  npCPMap
        localW  inx
cBegin

;/*
;** First we map hdc to lpAVioPS, the address for the AVIO PS.  We do this
;** by calling GreGetHandle for slot 1 and then validating the returned
;** value by calling VioGetPSAddress, which will return zero if it is
;** a valid PS address.
;*/

        check   GetHandle,<hdc,ulIndex,hddc,ulFunN>

        farPtr  null_hddc,0,0
        farPtr  myIndex,0,AVIO_PS_HANDLE_INDEX
        cCall   GreEntry4,<hdc,myIndex,null_hddc,GreGetHandle>
        mov     cx,ax
        or      cx,dx
        jnz     dsaf_50
        mov     ax,PMERR_INV_HDC
        jmp     error_exit_DeviceSetAVIOFont2

dsaf_50:

        mov     dx,ax
        save    <ds>                              ;Trashed by upward ring transition
        cCall   DosCallback,<ring3_GetPSAddress>
        mov     lpAVioPS.sel,dx
        mov     lpAVioPS.off,ax
        or      ax,dx                   ; lpAVioPS non-null?
        jnz     dsaf_100                ; then continue

        mov     ax,PMERR_INV_HDC        ; else error
        jmp     short error_exit_DeviceSetAVIOFont2
dsaf_100:

;/*
;** Next we examine the FontDef parameter to see if it defines a
;** usable font segment.
;*/

        mov     cx,FontDef.sel
        mov     ax,FontDef.off
        or      ax,cx
        jnz     non_null_fontdef

;/*
;** A null FontDef means that we should clear out the VioPS info
;** for the specified lcid.
;*/

        mov     npCPMap,ax
        jmp     verify_the_lcid_index

non_null_fontdef:

        jcxz    Bad_FontDef
        jmp     short dsaf_200

Bad_FontDef:
        mov     ax,PMERR_FONT_NOT_LOADED
        jmp     short error_exit_DeviceSetAVIOFont2

dsaf_200:
        cCall   ValidateSelector,<cx>             ; Valid selector?
        jc      Bad_FontDef
        inc     ax
        cmp     ax,(SIZE FOCAFONT)                ; Segment large enough?
        jb      Bad_FontDef

        lds     si,FontDef                         ; Offset must be zero!
        assumes ds,FontSeg

        mov     es,VioSegData
        assumes es,Data

        or      si,si
        jnz     Bad_FontDef

        test    fsMetrics.foca_fsTypeFlags,1     ; Fixed pitch font?
        jz      inv_font_attrs

;/*
;** The image shape for the font must match one of the supported cell shapes.
;** Check by searching the table of cell-sizes for a match.
;** The table is ordered by cell-size, width most-significant.
;*/

        mov     ax,fsDef.fdCellWidth            ; get requested cell-width
        mov     dx,fsDef.fdCellHeight           ; get requested cell-height

        mov     cx,cDevVioCells         ; get count of available sizes
        lea     bx,adDevVioCells        ; point to first entry in table

dsaf_230:
        cmp     ax,es:cf_width[bx]      ; if requested width less than...
        jb      inv_font_attrs          ; ...width from table it isn't in...
                                        ; ...the table
        ja      dsaf_250                ; if it's greater then try the next one

        cmp     dx,es:cf_height[bx]     ; if requested height matches then...
        je      acceptable_cell_shape   ; ...found it
        jb      inv_font_attrs          ; if it's less then it isn't in table

dsaf_250:
        add     bx,size CellFont        ; move to next entry
        loop    dsaf_230                ; iterate

inv_font_attrs:
        mov     ax,PMERR_INV_FONT_ATTRS

error_exit_DeviceSetAVIOFont2:
        save_error_code
        xor     ax,ax
        jmp     exit_DeviceSetAVIOFont2

;/*
;** Now we construct a reference to the code page mapping vector for this font.
;*/

        public  acceptable_cell_shape
acceptable_cell_shape:
        mov     ax,fsMetrics.foca_usCodePage     ; Set font's codepage

;/*
;** Use the logical font codepage if it is available
;** Because we may be simulating the old DeviceSetAVIOFont the pFattr parameter
;** may be NULL
;*/

        mov     bx,pFattr.sel
        or      bx,pFattr.off
        jz      dsaf_codepage_set

        push    ds
        lds     bx,pFattr
        mov     ax,fat_usCodePage[bx]
        pop     ds

dsaf_codepage_set:
        mov     cp,ax
        lea     bx,cp
        farPtr  pCPId,ss,bx
        lea     cx,npCPMap
        farPtr  pCPMap,ss,cx
        cCall   Force_Valid_CP,<pCPId,pCPMap>
        or      ax,ax
        jz      dsaf_300

        mov     ax, ERROR_VIO_BAD_CP
        jmp     short error_exit_DeviceSetAVIOFont2

dsaf_300:

;/*
;** Check the range of the LCID index
;*/

verify_the_lcid_index:

        mov     ax,inxLCID.sel
        inc     ax
        jz      dsaf_400

        mov     ax,PMERR_INV_SETID
        jmp     short error_exit_DeviceSetAVIOFont2

        public  dsaf_400
dsaf_400:
        mov     si,inxLCID.off
        not     si
        dec     si
        cmp     si,CNT_LOADABLE_LCIDS
        jb      dsaf_500

        mov     ax,PMERR_INV_SETID
        jmp     short error_exit_DeviceSetAVIOFont2

        public  dsaf_500
dsaf_500:
;/*
;** All OK.  Store the font selector and the mapping offset.
;*/

        mov     es,lpAVioPS.sel
        assumes es,nothing

        shl     si,1
        mov     ax,FontDef.sel
        mov     es:viops_selfontsloaded[si],ax
        mov     ax,npCPMap
        mov     es:viops_npmapfontsloaded[si],ax

        mov     ax,1

exit_DeviceSetAVIOFont2:

        xor     dx,dx                                ; Because our result is ULONG ?!?
cEnd

sEnd    VioSeg
end
