;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = WINATTRS.ASM
;*
;* DESCRIPTIVE NAME = Window Attributes functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/07/87
;*
;* DESCRIPTION  Window Attributes functions    
;*              
;* FUNCTIONS    SetStyleRatio 
;*              GetStyleRatio 
;*              SetLineOrigin  
;*              GetLineOrigin  
;*              RealizeFont
;*              SetPatternFont 
;*              DeviceQueryFontAttributes 
;*              GetPairKerningTable 
;*              NotifyClipChange
;*              ErasePS
;*              GetCodePage
;*              SetCodePage 
;*              DeviceQueryFonts
;*              NotifyTransformChange 
;*              Death
;*              Resurrection 
;*              GetDCOrigin 
;*              DeviceSetDCOrigin 
;*              DeviceInvalidateVisRegion 
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   07/16/87                      Hock Lee [hockl] Modified for new DDI.
;*   07/19/87                      Charles Whitmer [chuckwh] New DDI.
;*   08/12/87                      Hock Lee [hockl]
;*   08/12/87                      Returned base font if needed.
;*   09/11/87                      Hock Lee [hockl]
;*   09/11/87                      Changed to black default background color.
;*   09/28/87                      Hock Lee [hockl]
;*   09/28/87                      Used current background color to erase screen
;*   09/28/87                      instead of black.
;*   10/05/87                      Hock Lee [hockl] Invalidated ddc_corr_rect
;*   10/05/87                      when clip region changed.
;*   10/05/87                      Hock Lee [hockl]
;*   10/05/87                      Invalidated ddc_corr_rect when clip region
;*   10/05/87                      changed.
;*   10/05/87                      Hock Lee [hockl]
;*   10/05/87                      Invalidated ddc_corr_rect when transform
;*   10/05/87                      changed.
;*   10/11/87                      Hock Lee [hockl] Changed to black default
;*   10/11/87                      background color.
;*   10/28/87                      Hock Lee [hockl] Used current background color
;*   11/16/87                      Hock Lee [hockl] rewrote to use new bitblt.
;*   11/16/87                      Hock Lee [hockl] rewrote to use new bitblt.
;*   01/19/88                      Martin Picha [martinpi] Changed back to black
;*   01/19/88                      for erasing screen as per DCR 23428.
;*   01/19/88                      Martin Picha [martinpi]
;*   01/19/88                      Changed back to black for erasing screen as
;*   01/19/88                      per DCR 23428.
;*   01/31/88                      Charles Whitmer [chuckwh]
;*   01/31/88                      Rewrote to just copy the POINTL.
;*   02/16/88                      Hock Lee [hockl]
;*   02/16/88                      Clipped to all clipping primitives including
;*   02/16/88                      clip path and user defined clip region!
;*   02/22/88                      Bob Grudem [bobgru]
;*   02/22/88                      Now does user bounds collection.
;*   02/22/88                      Charles Whitmer [chuckwh]
;*   02/22/88                      Moved into Engine from Xforms component.
;*   03/02/88                      Walt Moore [waltm]
;*   03/02/88                      Return error if raster font selected or font
;*   03/02/88                      is huge
;*   03/03/88                      Jeff Parsons [jeffpar] Added restore_textvram
;*   03/03/88                      call.
;*   03/03/88                      Jeff Parsons [jeffpar] Added save_textvram call.
;*   03/03/88                      Jeff Parsons [jeffpar]
;*   03/03/88                      Added restore_textvram call.
;*   04/07/88                      Mike Harrington [mikehar]
;*   04/07/88                      Make this puppy sing.  Now it actually sets
;*   04/07/88                      the DDC correctly.
;*   04/08/88                      Walt Moore [waltm] Corrected it.  Now logs
;*   04/08/88                      an error if the high word of the code page
;*   04/08/88                      is invalid, or no mapping vector is found.
;*   04/08/88                      Now saves the code page regardless of whether
;*   04/08/88                      the default font is selected in or not.  Fixed
;*   04/08/88                      register trashing.
;*   04/20/88                      Brian Conte [brianc]
;*   04/20/88                      Wrote it, to match the default font, and
;*   04/20/88                      implemented DCR 23430.
;*   05/13/88                      Hock Lee [hockl] Used SYSCLR_WINDOW for
;*   05/13/88                      erasing screen as per DCR 23509.
;*   05/13/88                      Hock Lee [hockl]
;*   05/13/88                      Used SYSCLR_WINDOW for erasing screen as per
;*   05/13/88                      DCR 23509.
;*   05/16/88                      Hock Lee [hockl] Clipped to all clipping
;*   05/16/88                      primitives including clip path and user defined
;*   05/16/88                      clip region!
;*   05/24/88                      Bob Grudem [bobgru] SYSCLR_WINDOW only used
;*   05/24/88                      if color 0 hasn't been explicitly defined
;*   05/24/88                      Bob Grudem [bobgru]
;*   05/24/88                      SYSCLR_WINDOW only used if color 0 hasn't
;*   05/24/88                      been explicitly defined by user.
;*   06/17/88                      Hock Lee [hockl] Made it fully recoverable.
;*   06/20/88                      Bob Grudem [bobgru]
;*   06/20/88                      Returns 0 for style ratio if style is
;*   06/20/88                      LINETYPE_ALTERNATE.
;*   08/02/88                      Jeff Parsons [jeffpar] Death now relies on the
;*   08/02/88                      physical_enable routine to perform the
;*   08/02/88                      restore_textvram operation.  The return code
;*   08/02/88                      from restore_textvram becomes the return code
;*   08/02/88                      from physical_enable.
;*   08/02/88                      Jeff Parsons [jeffpar]
;*   08/02/88                      Now relies on the physical_enable routine to
;*   08/02/88                      perform the restore_textvram operation.  The
;*   08/02/88                      return code from restore_textvram becomes the
;*   08/02/88                      return code from physical_enable.
;*   08/05/88                      Jeff Parsons [jeffpar]
;*   08/05/88                      Now calls the new physical_disable routine.
;*   08/05/88                      No longer calls save_textvram directly.
;*   09/06/88                      Hock Lee [hockl]
;*   09/06/88                      Moved into DD from Engine component.
;*   10/08/88             DCR24139 Hock Lee [hockl] Implemented lazy vis region.
;*   10/22/88                      Bob Grudem [bobgru] Now does user bounds
;*   10/22/88                      collection.
;*   12/12/88             DCR24229 Wes Rupel [wesleyr] Font Caching problems
;*   12/12/88                      addressed
;*   12/12/88                      to erase screen instead of black.
;*   12/12/88                      Wes Rupel [wesleyr]
;*   12/12/88                     DCR 24229:  Font Caching problems addressed
;*                                                    
;*****************************************************************************/


        .286p
        .xlist
        include cmacros.inc
INCL_DDIMISC2           equ                      1
INCL_WINSYS             equ                      1
INCL_GRE_LINES          equ                      1
INCL_GRE_CLIP           equ                      1
INCL_DEV                equ                      1
INCL_GRE_BITMAPS        equ                      1
INCL_GRE_FONTS          equ                      1
INCL_GRE_DEVMISC        equ                      1
INCL_DDIMISC2           equ                      1
INCL_GRE_DEVMISC3       equ                      1
INCL_GRE_DEVSUPPORT     equ                      1
BOGUS                   equ                      1 
INCL_DDIBUNDLES         equ                      1
INCL_FONTFILEFORMAT     equ                      1
INCL_DDIMISC            equ                      1
INCL_GPIREGIONS         equ                      1
INCL_GPIBITMAPS         equ                      1
INCL_DDICOMFLAGS        equ                      1
INCL_TKTP               equ                      1
        include pmgre.inc
DINCL_ENABLE            equ                      1
DINCL_VIO               equ                      1
DINCL_PAT_CACHE_DEFS    equ                      1
        include driver.inc
        include display.inc
        include fontseg.inc
        include assert.mac
        include njmp.mac
        .list

        errcode <COORDINATE_OVERFLOW,KERNING_NOT_SUPPORTED,INV_CODEPAGE>
        errcode <INV_IN_PATH, INV_IN_AREA>
        errcode <INV_LENGTH_OR_COUNT,INV_HDC>
        errcode <HUGE_FONTS_NOT_SUPPORTED,INV_PATTERN_SET_FONT,INV_PATTERN_SET_ATTR>

        externFP        Bitblt
        externFP        GetCurrentPosition
        externFP        SetCurrentPosition
        externFP        GreEntry3
        externFP        FSRSemCheck

        externFP        far_physical_enable          ; initialize screen hardware
        externFP        far_physical_disable


sBegin  Data
        externB semDriver
        externB fGrimReaper
        externB sdScreen
        externW selDeathToUse
        externD pfnDefSelectClipRegion
        externD pfnDefGetClipRects
        externD pfnDefNotifyClipChange
        externD pfnDefNotifyTransformChange
        externD pfnDefGetPairKerningTable
        externD idBrushCache
        externW wSVGAtype
sEnd    Data

sBegin  Code
        assumes cs,Code

        externW         CodeData
        externNP        enter_driver
        externNP        enter_driver_sem
        externNP        leave_driver
        externNP        xform_pattern_origin
        externNP        convert_world_screen
        externNP        recalc_correlate_rect        ; MAJOR0B.ASM
        externNP        copy_bits_to_pattern         ; PHYCOLOR.ASM
ifdef FONT_CACHING
        externNP invalidate_font_cache
endif


page


;/***************************************************************************
;*
;* FUNCTION NAME = SetStyleRatio 
;*
;* DESCRIPTION   = sets the style stepping numbers in the DDC                     
;*
;*                 Registers Destroyed:
;*                       BX,CX,ES      
;*                 Registers Preserved:
;*                       SI,DI,DS,BP   
;*
;* INPUT         = hdc     :DWORD,
;*                 pbRatio :DWORD,
;*                 hddc    :DWORD,
;*                 FunN    :DWORD 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0   
;*
;**************************************************************************/

        check   SetStyleRatio,<hdc,psr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   SetStyleRatio,<PUBLIC,FAR,NODATA>
        parmD   hdc
        parmD   lpRatio
        parmD   hddc
        parmD   FunN
cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      ssr_exit_no_lock                 ; DX:AX = 0 on error

        les     bx,lpRatio
        assumes es,nothing
        mov     ax,es:[bx]

        mov     bx,hddc.lo
        mov     word ptr [bx].ddc_la.la_bStepX,ax
        .errnz  la_bStepY - la_bStepX - 1

        mov     ax,1
        cwd
        call    leave_driver
ssr_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = GetStyleRatio 
;*
;* DESCRIPTION   = gets the style stepping numbers from the DDC                     
;*
;*                 Registers Destroyed:
;*                       BX,CX,ES      
;*                 Registers Preserved:
;*                       SI,DI,DS,BP   
;*
;* INPUT         = hdc     :DWORD, 
;*                 lpRatio :DWORD, 
;*                 hddc    :DWORD, 
;*                 FunN    :DWORD  
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = style state (DX = 0, AH = y step, AL = x step)       
;* RETURN-ERROR  = DX:AX = -1 
;*
;**************************************************************************/

        check   GetStyleRatio,<hdc,psr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetStyleRatio,<PUBLIC,FAR,NODATA>
        parmD   hdc
        parmD   lpRatio
        parmD   hddc
        parmD   FunN
cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        mov     ax,-1                             ; assume error
        cwd
        jc      gsr_exit_no_lock

        mov     bx,hddc.lo
        .errnz  la_bStepY - la_bStepX - 1

        mov     ax,word ptr [bx].ddc_la.la_bStepX
        les     bx,lpRatio
        assumes es,nothing
        mov     es:[bx],ax

        mov     ax,1
        cwd
        call    leave_driver
gsr_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = SetLineOrigin 
;*
;* DESCRIPTION   = sets the style state in the DDC                                  
;*
;*                 Registers Destroyed:
;*                       BX,CX,ES      
;*                 Registers Preserved:
;*                       SI,DI,DS,BP   
;*
;* INPUT         = lpXY     = new current position
;*                 Style.lo = style info          
;*                 Style.hi = first pel info      
;* OUTPUT        =
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0 
;*
;**************************************************************************/

        check   SetLineOrigin,<hdc,pptl,lStyleState,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   SetLineOrigin,<PUBLIC,FAR,NODATA>
        parmD   hdc
        parmD   lpXY
        parmD   Style
        parmD   hddc
        parmD   FunN
cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      slo_exit_no_lock                 ; DX:AX = 0 on error

;/*
;** Clear the COM_AREA and COM_PATH bits from the FunN.hi.  The procedures
;** that call here already have taken the path cookie.
;*/

        mov     bx,FunN.hi
        and     bx,NOT (COM_AREA or COM_PATH)
        farPtr  MyFunN,bx,off_SetCurrentPosition
        check   SetCurrentPosition,<hdc,pptl,hddc,ulFunN>
        cCall   SetCurrentPosition,<hdc,lpXY,hddc,MyFunN>
        or      ax,ax
        jz      slo_exit

        mov     bx,hddc.lo
        mov     ax,Style.lo                       ; AL = mask pos, AH = error
        xchg    al,ah                             ; AL = error, AH = mask pos
        mov     word ptr [bx].ddc_la.la_bError,ax
        .errnz  la_bMask - la_bError - 1
        and     [bx].ddc_fb,not DDC_FIRST_PEL
        mov     ax,Style.hi
        or      ax,ax
        jz      slo_done
        or      [bx].ddc_fb,DDC_FIRST_PEL
slo_done:
        mov     ax,1
slo_exit:
        cwd
        call    leave_driver
slo_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = GetLineOrigin
;*
;* DESCRIPTION   = gets the style state and current position from the DDC        
;*
;*                 Registers Destroyed: 
;*                       BX,CX,ES       
;*                 Registers Preserved: 
;*                       SI,DI,DS,BP    
;*
;* INPUT         =  hdc     :DWORD
;*                  lpXY    :DWORD
;*                  pddc    :DWORD
;*                  FunN    :DWORD
;* OUTPUT        =
;*
;* RETURN-NORMAL = AX = AH = style error, AL = position in mask   
;*                 DX = 0 => no first pel, 1 => first pel drawn.  
;* RETURN-ERROR  =  DX:AX = -1   
;*
;**************************************************************************/

        check   GetLineOrigin,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetLineOrigin,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   lpXY
        parmD   hddc
        parmD   FunN
cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        mov     ax,-1                             ; assume error
        cwd
        jc      glo_exit_no_lock

        check   GetCurrentPosition,<hdc,pptl,hddc,ulFunN>
        farPtr  MyFunN,FunN.hi,off_GetCurrentPosition
        cCall   GetCurrentPosition,<hdc,lpXY,hddc,FunN>

        mov     bx,hddc.lo
        mov     ax,word ptr [bx].ddc_la.la_bError
        .errnz  la_bMask - la_bError - 1
        xchg    al,ah                             ; AL = mask pos, AH = error
        xor     dx,dx
        test    [bx].ddc_fb,DDC_FIRST_PEL         ; DX = first pel info
        jz      @F
        inc     dx
@@:     call    leave_driver
glo_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = RealizeFont     
;*
;* DESCRIPTION   = Calls invalidate font cache
;*                 
;*                 Registers Destroyed:   
;*                       AX,BX,CX,DX,ES   
;*                 Registers Preserved:   
;*                       SI,DI            
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 0  
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   RealizeFont,<hdc,ulCmd,pfatLogFont,pfocaEngFont,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   RealizeFont,<PUBLIC,FAR,NODATA>,<ds,si,di>

        parmD   hdc
        parmD   Command
        parmD   LogFont
        parmD   EngFont
        parmD   hddc
        parmD   FunN
        localV  Points,%((SIZE POINTL)*2)
        localW  Work

cBegin

ifdef FONT_CACHING
        mov     ds,CodeData
        assumes ds,Data
        call    enter_driver_sem                 ; don't call back PMWIN!
        jc      rf_exit_no_lock                  ; DX:AX = 0 on error
        assert  Command.hi,E,0
        cmp     Command.lo,RF_DELETE_ENGINE_FONT and 0FFFFh
        jne     realizefont_exit
        mov     ax,EngFont.sel
        mov     bx,hddc.lo
        ddc?    bx
        call    invalidate_font_cache
realizefont_exit:
        call    leave_driver
rf_exit_no_lock:
endif
        xor     ax,ax
        cwd
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = SetPatternFont      
;*
;* DESCRIPTION   = Deals with font selection/bitmap bits for patterns.  This 
;*                 routine will not be called when the base pattern set is 
;*                 selected.
;*
;*                 Registers Preserved:    
;*                       BX,CX,SI,DI,BP,DS 
;*                 Registers Destroyed:    
;*                       AX,DX,ES,FLAGS    
;*                 Calls:
;*                       copy_bits_to_pattern
;*
;* INPUT         = EBX -> ddc                                            
;*                 EDX -> FOCAFONT, or SURFACE(BITMAP)  
;*                 BP  =  attr index for characters                      
;*                 ESI -> DAREABUNDLE attribute bundle                   
;*                 PA_BITMAP_SRC and PA_COLOR_TRUTH bits clear in
;*                                        ddc->ddc_pa.pa_ba.ba_fb
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1    
;* RETURN-ERROR  = AX = 0        
;*                 error logged  
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing


cProc   SetPatternFont,<PUBLIC,FAR,NODATA>,<cx,si,di>
cBegin
        ddc?    bx

;/*
;** Check whether we have a bitmap or a font.
;*/

        add     si,es:[si].dabnd_cAttr
        add     si,(SIZE dabnd_cDefs + SIZE dabnd_cAttr)
        cmp     es:[si].adef_defSet.sel,HDBM_IDENT
        jnz     spf_font
        jmp     spf_bitmap


;/*
;**   We have a font.  Set the codepage id, and get the codepage mapping
;**   vector if needed.  Set the following flags if needed (* --> always set):
;**  
;**         CA_MUST_MAP, CA_ABC_SPACING, CA_CHANGED (*), CA_USER_FONT (*)
;**         BA_REREALZE (*)
;**  
;**   Return errors in case of:
;**  
;**         vector font
;**         huge font (> 64K)
;**         failure reading codepage mapping vector
;**  
;**   We need to set the flags to make the brush realization code do
;**   something.  The PA_BITMAP_SRC and PA_COLOR_TRUTH bits have already
;**   been cleared by the caller.
;**  
;**   We can ignore the offset to the font because we FIREWALLed it to be
;**   zero, and all our code would fall apart if it wasn't.
;*/

spf_font:
ifdef FIREWALLS
        mov     [bx].ddc_pa.pa_paus.sel,INVALID_SEL
endif

xyzzy   equ     CDEF_STRIKEOUT or CDEF_UNDERSCORE or CDEF_ITALIC or CDEF_BOLD
        test    es:[si].adef_fFlags,xyzzy
        jnz     spf_bad_font_attrs
        mov     si,es:[si].adef_CodePage
        mov     cx,[bx].ddc_pa.pa_fs

        access  ax,dx                             ;avoid GP faults when peeking
        mov     es,dx
        assumes es,FontSeg
        test    fsMetrics.foca_fsTypeFlags,FM_TYPE_64K
        jnz     spf_huge_font

        test    fsMetrics.foca_fsDefn,FM_DEFN_OUTLINE ; Vector Font
        jnz     spf_bad_font

        cmp     fsDef.fdh_fsChardef,FONTDEFCHAR3
        jne     @F
        or      cx,CA_ABC_SPACE
@@:

;/*
;** If the font is not in the default code page (850), then no mapping
;** is possible.  If the font is the default code page and a different
;** code page is to be used, get the mapping array.  If getting the
;** mapping array fails, return an error.
;*/

        cmp     fsMetrics.foca_usCodePage,DEFAULTVIOCODEPAGE
        jne     spf_font_done
        cmp     si,DEFAULTVIOCODEPAGE
        je      spf_font_done
        or      si,si                             ;0 = use the default in the font
        je      spf_font_done

;/*
;** Get the mapping vector for this code page.  Don't bother to get access
;** now since the access test has to be made at output time.
;*/

        check   QueryCodePageVector,<idCP,hddc,ulFunN>
        save    <bx,cx>
        xor     dx,dx
        farPtr  myCPID,dx,si
        farPtr  myhddc,dx,dx
        cCall   GreEntry3,<myCPID,myhddc,GreQueryCodePageVector>
        mov     [bx].ddc_pa.pa_paus.sel,dx
        mov     [bx].ddc_pa.pa_paus.off,ax
        or      ax,dx
        jz      spf_exit_vect                     ;Error, return 0
        or      cx,CA_MUST_MAP

spf_font_done:
        or      [bx].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        or      cx,CA_CHANGED or CA_USER_FONT
        mov     [bx].ddc_pa.pa_fs,cx
        mov     ax,1
spf_exit_vect:
        jmp     spf_exit

;/*
;** Log the error and exit
;*/

spf_bad_font_attrs:
        mov     ax,PMERR_INV_PATTERN_SET_ATTR
        jmp     short spf_error

spf_bad_font:
        mov     ax,PMERR_INV_PATTERN_SET_FONT
        jmp     short spf_error

spf_huge_font:
        mov     ax,PMERR_HUGE_FONTS_NOT_SUPPORTED
spf_error:
        save_error_code
        xor     ax,ax
        jmp     spf_exit



;/*
;** We have a bitmap to copy into the pattern attributes structure.
;** Before anything else, check that its handle is valid, that the
;** surface is indeed a bitmap, and that it is neither null nor huge.
;** Of all those checks, only null or huge bitmaps are considered
;** errors to be returned to the caller, the others being internal errors
;** worthy of rips.
;*/

spf_bitmap:
        mov     di,ax                             ;move bitmap handle into index reg


ifdef FIREWALLS
;/*
;** Make sure the bitmap belongs to us.  If not, the engine screwed up.
;*/

        cmp     dx,HDBM_IDENT
        jne     spf_bad_handle
        cmp     [di].bm_sd.sd_usId,SURFACE_IDENT
        jne     spf_bad_handle
        test    [di].bm_sd.sd_fb,SD_DEVICE
        jz      spf_bitmap_handle_ok

spf_bad_handle:
        rip     text,<A bad bitmap handle came into SetPatternFont>
        xor     ax,ax
        jmp     short spf_exit

spf_bitmap_handle_ok:
endif


;/*
;** Make sure that we have a handle to bits if the bitmap is non-null.
;** Exit with an error if the bitmap is null or huge.
;*/

        test    [di].bm_sd.sd_fb,SD_NONNULL
        jz      spf_bad_font                          ;it's a null bitmap --> no bits
        test    [di].bm_sd.sd_fb,SD_HUGE
        jnz     spf_bad_font                          ;it's a huge bitmap --> get out
ifdef FIREWALLS
        cmp     [di].bm_sd.sd_pBits.sel,0   ;must have non-null selector
        jnz     spf_selector_ok

        rip     text,<A null bitmap selector came into SetPatternFont>
        xor     ax,ax
        jmp     short spf_exit
spf_selector_ok:
endif


;/*
;** Now that we believe the bitmap is valid, set up a call to copy the
;** bits based on whether it is in color or is monochrome.
;*/

        test    [di].bm_sd.sd_fb,SD_COLOR
        jz      spf_mono_bitmap

        or      [bx].ddc_pa.pa_fb,PA_BITMAP_SRC or PA_COLOR_TRUTH
        lea     si,[bx].ddc_pa.pa_abColor
        mov     cl,4
        jmp     short spf_copy_bitmap_bits

spf_mono_bitmap:
        or      [bx].ddc_pa.pa_fb,PA_BITMAP_SRC
        lea     si,[bx].ddc_pa.pa_abMask
        mov     cl,1


;/*
;** Set up the registers as follows:
;**
;**       AL     =  number of color planes
;**       AH     =  width in pels
;**       DS:BX --> DDC
;**       CX     =  number of bytes per scan
;**       DX     =  height in scans
;**       DS:SI --> destination of bits
;**       ES:DI --> source bits
;**
;** The width is truncated to 8 pels to make it fit in a byte.  It is only
;** needed to determine if the bitmap fills the entire pattern bits buffer.
;** The access macro is called to prevent GP faults (which will happen
;** without it!!).
;**
;** The brush realization code looks at the BA_REREALIZE and CA_CHANGED
;** bits in the pattern attributes to determine if the brush bits need
;** to be rerealized, so make sure we set these!
;*/

spf_copy_bitmap_bits:
        mov     ax,[di].bm_sd.sd_pBits.sel        ;want ES:DI ptr to source bits
        mov     es,ax
        assumes es,nothing
        mov     ax,[di].bm_sd.sd_cx               ;width of source bitmap
        push    bx                                ;save work register
        mov     bx,PATTERN_WIDTH                  ; 
        usmin_ax   bx                             ;make sure width fits in a byte
        pop     bx                                ;restore DDC
        mov     ah,al                             ;copy_bits... wants width here
        mov     al,cl                             ;  and wants plane cnt here
        mov     cx,[di].bm_sd.sd_cbScan           ;get bytes per scan line
        mov     dx,[di].bm_sd.sd_cy               ;height of source bitmap
        mov     di,[di].bm_sd.sd_pBits.off        ;offset of source bits
spf_copy_bits:
        cCall   copy_bits_to_pattern
        or      [bx].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        or      [bx].ddc_pa.pa_fs,CA_CHANGED
        mov     ax,1

spf_exit:
cEnd


sEnd    Code
sBegin  BlueMoon
        assumes cs,BlueMoon

        externW BlueMoonData

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceQueryFontAttributes 
;*
;* DESCRIPTION   = This obtains the metrics of the currently selected font.       
;*
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,ES  
;*
;* INPUT         = lpMetrics                                                        
;*                     A long pointer to a font metric block where the information  
;*                     is to be returned.                                           
;*                 iMetrics                                                         
;*                     The size of the data structure pointer at by lpMetrics       
;*                 hdc                                                              
;*                     The DC handle.                                               
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX   = 1 if the function executed successfully  
;* RETURN-ERROR  = AX      = 0 
;*
;*             ---------Pseudo-Code---------
;* short FAR DeviceQueryFontAttributes(iMetrics, lpMetrics, hdc, FunN)
;* {
;*   copy the metrics from current font handle in ddc
;*
;*   Copy(dst,src,nbytes)
;*   Copy(lpMetrics,
;*        &ddc->ddc_char_font->foca_szFamilyname,
;*        min(iMetrics,ddc->ddc_char_font->foca_ulSize));
;*
;*
;*   return success
;* }
;*
;**************************************************************************/

        check   DeviceQueryFontAttributes,<hdc,cbFontMetrics,pfm,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

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

        parmD   hdc
        parmD   iMetrics
        parmD   lpMetrics
        parmD   hddc
        parmD   FunN

        localV  tm,%(size FONTMETRICS)

cBegin


        xor     ax,ax
        cwd
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = GetPairKerningTable     
;*
;* DESCRIPTION   =
;*
;*                 Registers Destroyed: 
;*                       AX,BX,CX,DX,ES 
;*
;* INPUT         = hdc             :DWORD
;*                 Count           :DWORD
;*                 lpKernPairs     :DWORD
;*                 pddc            :DWORD
;*                 FunN            :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   GetPairKerningTable,<hdc,ckp,pkp,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetPairKerningTable,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   Count
        parmD   lpKernPairs
        parmD   hddc
        parmD   FunN

cBegin
        ddc?    hddc
        mov     ds,BlueMoonData
        assumes ds,Data
        mov     si,hddc.lo
        test    [si].ddc_ca.ca_fs,CA_USER_FONT
        jz      gpkt_our_font
        cleanframe
        assumes ds,nothing
        mov     es,BlueMoonData
        assumes es,Data
        jmp     pfnDefGetPairKerningTable

gpkt_our_font:
        assumes es,nothing
        assumes ds,Data
        mov     ax,0                              ; assume success.
        cmp     Count.hi,0
        jge     @F 
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        save_error_code
        xor     ax,ax
        dec     ax
@@:
        cwd

cEnd

sEnd    BlueMoon

;/***************************************************************************
;*
;* FUNCTION NAME = NotifyClipChange          
;*
;* DESCRIPTION   = This function is called whenever the clip region intersected 
;*                 with the visible region is changed. We always store the first 
;*                 NUM_CLIP_RECTS in our ddc. If NCC_CLEANDC is set, the ddc is 
;*                 no longer dirty.  This is required to implement lazy vis 
;*                 region.  
;*
;* INPUT         = hdc     :DWORD
;*                 prcl    :DWORD
;*                 crcl    :DWORD
;*                 Flags   :DWORD
;*                 pddc    :DWORD
;*                 FunN    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

sBegin  Code
        assumes cs,Code

        check   NotifyClipChange,<hdc,prcl,crcl,flCmd,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

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

        parmD   hdc
        parmD   prcl
        parmD   crcl
        parmD   Flags
        parmD   hddc
        parmD   FunN

        localV  RectBuffer,<size RECTL * NUM_CLIP_RECTS>
        localV  Control,<size RGNRECT>

cBegin
        ddc?    hddc,<SURFACE>
        cld
        mov     ds,CodeData
        assumes ds,Data

;/*
;** This call only makes sense with the device locked, check it out!
;*/

        mov     di,hddc.lo                         ; ds:di --> ddc
        push    ds
        pop     es
        assumes es,Data

;/*
;** get number of rectangles in the new region.
;*/

        assert  Flags.hi,E,0
        assert  Flags.lo,BE,NCC_CLEANDC
        test    Flags.lo,NCC_CLEANDC               ; clear dc dirty bit?
        jz      @F                                 ;   no
ifdef FIREWALLS
        cCall   FSRSemCheck,<DataOFFSET semDriver>
        or      ax,dx
        jz      ncc_dev_is_locked
        rip     text,<NotifyClipChange called without LockDevice>
ncc_dev_is_locked:
        test    [di].ddc_fbAbove,DDC_DIRTY_VISRGN
        jnz     ncc_dev_is_dirty
        puts    <NotifyClipChange: DC is not dirty>
ncc_dev_is_dirty:
endif
        and     [di].ddc_fbAbove,NOT DDC_DIRTY_VISRGN
        jmp     ncc_good_exit
@@:
        mov     cx,crcl.lo
        jcxz    got_a_rect                         ; 0 rect
        cmp     cx,1                               ; 1 rect
        jne     get_all_rects

;/*
;** we have only one rect here which is our lpRect.
;*/

one_rects:

        lds     si,prcl
        assumes ds,nothing
got_a_rect:
        jmp     short got_rects

;/*
;** we have more than one and at most NUM_CLIP_RECTS, get them all.
;*/

get_all_rects:

;/*
;** Get clip rectangles
;*/

        xor     ax,ax
        mov     Control.rgnrc_ircStart,1
        mov     Control.rgnrc_crcReturned,ax
        mov     Control.rgnrc_crc,NUM_CLIP_RECTS
        mov     Control.rgnrc_usDirection,RECTDIR_LFRT_BOTTOP

        check   GetClipRects,<hdc,prclBounds,prgnrc,prclClip,hddc,ulFunN>
        lea     bx,Control
        lea     cx,RectBuffer
        farPtr  lp_rect,ax,ax                     ;No bounding rectangle
        farPtr  lp_ctrl,ss,bx
        farPtr  lp_list,ss,cx
        farPtr  hddcNull,0,0
        cCall   pfnDefGetClipRects,<hdc,lp_rect,lp_ctrl,lp_list,hddcNull,GreGetClipRects>

ifdef FIREWALLS
        test    ax,ax
        jnz     get_clip_rects_ok
        rip     text,<GetClipRects returns error>
get_clip_rects_ok:
endif

        mov     cx,crcl.lo                        ;CX = num of clip rects

ifdef FIREWALLS
        cmp     cx,Control.rgnrc_crcReturned
        je      clip_rects_ok
        cmp     cx,NUM_CLIP_RECTS
        ja      clip_rects_ok
        rip     text,<GetClipRects returns error>
clip_rects_ok:
endif

        lea     si,RectBuffer
        push    ss                                
        push    ds                                
        pop     es
        pop     ds

;/*
;** ds:si = Clip Rects
;** es:di = ddc
;** cx = n clip rects
;** ddc_ncliprects is the number of clip rects (can be more than NUM_CLIP_RECTS)
;*/

got_rects:
        mov     ax,cx
        add     di,ddc_crcsClip
        stosw
        jcxz    all_saved
        cmp     cx,NUM_CLIP_RECTS
        jbe     save_rects                        ; 1 <= cx <= NUM_CLIP_RECTS

; we have too many rects here, save only the first NUM_CLIP_RECTS rects.

        mov     cx,NUM_CLIP_RECTS                 ; > NUM_CLIP_RECTS

;/*
;** store the clip rects
;*/

save_rects:
        les     di,es:[di][-ddc_crcsClip-2].ddc_prddc
        rddc?   es,di
        add     di,rddc_arcsClip
        shl     cx,2                              ; 4 sides per rectangle

save_rects_loop:
        movsw                                     ;!!! wheres the FIREWALL for the
        inc     si                                ;!!! .hi portion????
        inc     si
        loop    save_rects_loop

all_saved:
        mov     ds,CodeData
        assumes ds,Data                           ; restore ds, for leave_driver!!!
        mov     di,hddc.lo
        mov     al,[di].ddc_fb
        or      al,DDC_CLIP_NOTIFY                ;Have been notified
        and     al,not DDC_VISIBLE                ;Assume nothing shows
        cmp     [di].ddc_crcsClip,1
        jb      ncc_1701                          ;I'm a trekie
        test    al,DDC_PRESENT                    ;Do we have a surface?
        jz      ncc_1701                          ;  No, so it cannot be visible
        mov     bx,[di].ddc_npsd                  ;  Yes, see if it is null
        test    [bx].sd_fb,SD_NONNULL
        jz      ncc_1701
        or      al,DDC_VISIBLE
ncc_1701:
        mov     [di].ddc_fb,al
ncc_good_exit:
        mov     ax,1
        cwd
        mov     ax,ds
        mov     es,ax
        assumes es,Data
        cleanframe
        assumes ds,nothing
        jmp     pfnDefNotifyClipChange

cEnd    <nogen>


;/***************************************************************************
;*
;* FUNCTION NAME = ErasePS                              
;*                                                       
;* DESCRIPTION   = Erases the output media associated with the specified DC 
;*                 handle to the color defined by SYSCLR_WINDOW.
;*
;*                 This operation is unaffected by the draw process control 
;*                 bit and is subject to all clipping (i.e. clip path, viewing
;*                 limits, graphics field, clip region and vis region).
;*
;*                 In order to erase a media subjected only to environmental 
;*                 clipping (i.e. clipping that is independent of any graphics 
;*                 segments), the clip path and viewing limits must be reset 
;*                 explicitly before the erase is issued. 
;*
;* INPUT         =  hdc     :DWORD
;*                  pddc    :DWORD
;*                  FunN    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1
;* RETURN-ERROR  = AX = 0
;*
;*                  -----------Pseudo-Code------
;* BOOL FAR PASCAL ErasePS(hdc,FunN)
;* {
;*   GreBitblt(0,2,{MINSHORT,MINSHORT,MAXSHORT,MAXSHORT},BLACKNESS,BLTMODE_ATTRS_PRES,
;*               {12,SYSCLR_WINDOW,SYSCLR_WINDOW},hdc);
;*
;*   return 1;
;* }
;*
;**************************************************************************/

        check   ErasePS,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   ErasePS,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   hddc
        parmD   FunN
        localW  old_pa_fs
        localB  old_pa_ch
        localB  old_pa_fb
        localV  old_bits,%(SIZE_PATTERN*(BITS_PEL+2)) ;color/mono/mask
cBegin
        cld
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                        ; SI = ddc
        mov     dx,si
        call    enter_driver
        njc     eps_exit_no_lock                 ; DX:AX = 0 on error

        no_path_area    erase_ps_exit,both,cwd

;/*
;** Save and set some goodies in ddc for BitBlt
;*/

        mov     al,PATSYM_SOLID                   ; set code point to solid
        xchg    al,[si].ddc_pa.pa_ch
        xchg    al,old_pa_ch

        mov     ax,CA_CHANGED                     ; code point has changed
        xchg    ax,[si].ddc_pa.pa_fs
        xchg    ax,old_pa_fs

        xor     al,al                             ; walt says so
        xchg    al,[si].ddc_pa.pa_fb
        mov     old_pa_fb,al

;/*
;** If the pattern came from a bitmap, then we must save the bits
;** before calling Bitblt.  The change of codepoint to PATSYM_SOLID
;** will cause the color bits to be updated (i.e. the whole purpose of
;** if anyway).  Our only record of any bitmap bits set into a pattern
;** are the pattern bits themselves, so save 'em.
;*/

        test    al,PA_BITMAP_SRC
        jz      eps_pattern_bits_restorable

        mov     cx,(SIZE_PATTERN * (BITS_PEL+2))/2
        lea     dx,[si].ddc_pa.pa_abColor
        test    al,PA_COLOR_TRUTH
        jnz     eps_have_source
        mov     cx,(SIZE_PATTERN)/2
        lea     dx,[si].ddc_pa.pa_abMask

eps_have_source:
        push    si                                ;save pointer to DDC
        mov     si,dx                             ;store source address in SI
        mov     ax,ss
        mov     es,ax
        assumes es,nothing
        lea     di,old_bits
        rep     movsw
        pop     si                                ;restore pointer to DDC

eps_pattern_bits_restorable:

;/*
;** Clear screen to SYSCLR_WINDOW
;*/

        mov     di,sp                             ; DI = old SP

;/*
;**!!! want to check these to make sure they are in the correct order!!!
;*/

        mov     ax,MAXSHORT
        cwd
        push    dx                                ; TargY2
        push    ax
        push    dx                                ; TargX2
        push    ax
        xor     ax,ax
        cwd
        push    dx                                ; TargY1
        push    ax
        push    dx                                ; TargX1
        push    ax
        mov     cx,sp                             ; BitBltParm in reverse stack order

;/*
;** lpAttrs
;**
;** If we are in indexed color mode and color 0 has been explicitly
;** redefined, then we will use color 0.           Otherwise, we will use
;** SYSCLR_WINDOW  (If color 0 hasn't been redefined, then it is
;** SYSCLR_WINDOW;  and, in RGB mode, color 0 cannot be redefined).
;*/

        mov     ax,SYSCLR_WINDOW
        test    [si].ddc_fbClrTbl,DDC_USER_CLR_0
        jz      @F
        xor     ax,ax
@@:
        cwd
        push    dx                                ; background color
        push    ax
        push    dx                                ; foreground color
        push    ax
        push    0                                 ; size word
        push    12
        mov     bx,sp                             ; Attrs in reverse order

        check   Bitblt,<hdc,hdcSrc,cptl,pbbp,lMix,flCmd,pbba,hddc,ulFunN>

        xor     ax,ax
        mov     dx,FunN.hi
        and     dx,COM_DRAW or COM_ALT_BOUND
        or      dx,COM_TRANSFORM                  ;The points are in device coords
        farPtr  src_dc,ax,ax                      ;No source DC
        farPtr  pt_cnt,ax,2                       ;Only two points
        farPtr  lp_rect,ss,cx                     ;--> to the rectangle
        farPtr  the_mix,ax,ROP_PATCOPY
        farPtr  my_style,<BLTMODE_ATTRS_PRES shr 16>,ax  
        .errnz  BLTMODE_ATTRS_PRES - 20000h
        farPtr  my_attrs,ss,bx
        farPtr  fun_num,dx,off_Bitblt
        cCall   Bitblt,<hdc,src_dc,pt_cnt,lp_rect,the_mix,my_style,my_attrs,hddc,fun_num>
        mov     sp,di                             ; restore SP

;/*
;** Restore ddc goodies, do not destory DX:AX
;*/

        xchg    bl,old_pa_ch
        xchg    bl,[si].ddc_pa.pa_ch

        xchg    bx,old_pa_fs
        or      bx,CA_CHANGED                     ; code point has changed
        xchg    bx,[si].ddc_pa.pa_fs

        xchg    bl,old_pa_fb
        or      bl,BA_REREALIZE                  ; must redo pattern before using it
        mov     [si].ddc_pa.pa_fb,bl

;/*
;** If we had to save the bits coming in, we'd better restore them
;** going out.
;*/

        test    bl,PA_BITMAP_SRC
        jz      erase_ps_exit

        push    ds

        mov     cx,(SIZE_PATTERN * (BITS_PEL+2))/2
        lea     di,[si].ddc_pa.pa_abColor
        test    bl,PA_COLOR_TRUTH
        jnz     eps_have_dest
        mov     cx,(SIZE_PATTERN)/2
        lea     di,[si].ddc_pa.pa_abMask

eps_have_dest:
        mov     bx,ds
        mov     es,bx
        assumes es,Data
        mov     bx,ss
        mov     ds,bx
        assumes ds,nothing
        lea     si,old_bits
        rep     movsw

        pop     ds

erase_ps_exit:
        assert  ax,BE,1
        assert  dx,E,0
        call    leave_driver
eps_exit_no_lock:
        fw_zero <es,cx>

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = GetCodePage                
;*
;* DESCRIPTION   = This obtains the current code page.                            
;*
;* INPUT         = hdc     :DWORD
;*                 pddc    :DWORD
;*                 FunN    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = current code page           
;* RETURN-ERROR  = DX:AX = 0     
;*
;*                     --------Pseudo-Code-----
;* LONG FAR PASCAL GetCodePage(hdc,FunN)
;* {
;*   return ddc_code_page;
;* }
;*
;**************************************************************************/

        check   GetCodePage,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetCodePage,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   hddc
        parmD   FunN

cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     bx,hddc.lo
        mov     ax,[bx].ddc_ca.ca_idCodePage
        cwd
        fw_zero <es,cx>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = SetCodePage
;*
;* DESCRIPTION   = This sets the code page to be used for the default font.  
;*
;*                 Registers Preserved:        
;*                       SI,DI,DS,BP           
;*                 Registers Destroyed:        
;*                       AX,BX,CX,DX,ES,FLAGS  
;*
;* INPUT         = hdc             :DWORD
;*                 CodePage        :DWORD
;*                 pddc            :DWORD
;*                 FunN            :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1     
;* RETURN-ERROR  = AX = 0 
;*
;**************************************************************************/

        check   SetCodePage,<hdc,idCP,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   SetCodePage,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   CodePage
        parmD   hddc
        parmD   FunN

cBegin
        ddc?    hddc
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      scp_exit_no_lock                 ; DX:AX = 0 on error
        no_path_area    scp_cwd,area

;/*
;**  If the code page isn't the default code page, then make the call to
;**  get the vector just to see if it is there.  If it is, then this is
;**  a valid code page.  If not, it's an error.  If it is a valid code
;**  page, then if the default font is in use, we'll have to use it.
;** 
;**  The Engine (if written correctly) will validate the high word of
;**  the code page and log any invalid code page error.
;*/

        cmp     CodePage.hi,DEFAULTVIOCODEPAGE shr 16
        jne     scp_get_vector
        mov     dx,INVALID_ADDRESS shr 16
        mov     ax,INVALID_ADDRESS and 0FFFFh
        cmp     CodePage.lo,DEFAULTVIOCODEPAGE and 0FFFFh
        je      scp_have_vector

scp_get_vector:
        check   QueryCodePageVector,<idCP,hddc,ulFunN>
        farPtr  hddcNull,ax,ax
        cCall   GreEntry3,<CodePage,hddcNull,GreQueryCodePageVector>
        mov     cx,ax
        or      cx,dx
        jz      scp_exit                          ;Error logged by QueryCodePageVector

;/*
;** The code page is valid.  Save it.  If the default font is in use,
;** then we must use this vector for translation.
;*/

scp_have_vector:
        mov     bx,hddc.lo
        mov     cx,CodePage.lo
        mov     [bx].ddc_ca.ca_idCodePage,cx
        test    [bx].ddc_ca.ca_fs,CA_USER_FONT
        jnz     scp_good_exit                     ;User font, don't use vector yet
        mov     [bx].ddc_ca.ca_paus.hi,dx
        mov     [bx].ddc_ca.ca_paus.lo,ax
        mov     ax,[bx].ddc_ca.ca_fs
        or      ax,CA_CHANGED or CA_MUST_MAP
        cmp     cx,DEFAULTVIOCODEPAGE and 0FFFFh
        jne     scp_have_flags
        and     ax,NOT CA_MUST_MAP
scp_have_flags:
        mov     [bx].ddc_ca.ca_fs,ax

scp_good_exit:
        mov     ax,1
scp_cwd:
        cwd
scp_exit:
        call    leave_driver
scp_exit_no_lock:
        fw_zero <es,cx>
cEnd

sEnd    Code

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceQueryFonts      
;*
;* DESCRIPTION   = Enumerates the fonts on a device. For each font on the device
;*                 the function returns the metrics of the the font
;*                 
;* INPUT         = lpFilter                                                           
;*                      The facename to match                                         
;*                                                                                    
;*                 iMetrics                                                           
;*                     The number of bytes of each metrics structure in the           
;*                     lpMetrics array.                                               
;*                                                                                    
;*                 lpMetrics                                                          
;*                      A long pointer to an array of textmetric records              
;*                                                                                    
;*                 lpiFonts                                                           
;*                      The number of fonts for which the application wants           
;*                      metrics. The number the application received is returned 
;*                      here.                                                               
;*                 All sizes are returned in world coordinates                        
;*                 In future we are going to have to back transform 
;*                 the metrics of the font                          
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ax =  The number of fonts the appl didn't get. This allows the 
;*                       appl to find out how many fonts there are by setting 
;*                       iFonts = 0.
;* RETURN-ERROR  = AX = -1     
;*
;**************************************************************************/

sBegin  Code
        assumes cs,Code

        check   DeviceQueryFonts,<hdc,flCmd,pszFaceName,pfm,cbFontMetrics,pcFonts,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

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

        parmD   hdc
        parmD   Options
        parmD   lpFilter
        parmD   lpMetrics
        parmD   iMetrics
        parmD   lpiFonts
        parmD   hddc
        parmD   FunN

        localV  tm,%(size FONTMETRICS)

cBegin
        cld
        mov     ds,CodeData
        assumes ds,Data
        call    enter_driver_sem                  ; Do not do a VisRegionCallBack
        mov     ax,-1                             ; assume error
        cwd
        jc      dgf_exit_no_lock

;/*
;** We don't have any fonts that we manage
;** so return 0 fonts left and 0 fonts returned
;*/

        les     di,lpiFonts
        xor     ax,ax
        stosw

dqf_exit:
        mov     cx,DataBASE
        mov     ds,cx
        assumes ds,Data                           
        cwd
        call    leave_driver
dgf_exit_no_lock:
        fw_zero <es,cx>
cEnd

sEnd    Code


;/***************************************************************************
;*
;* FUNCTION NAME = NotifyTransformChange 
;*
;* DESCRIPTION   = 
;*         This function is called whenever the transform change.
;*         It must be fully recoverable so that it can back out all changes
;*         if it fails.  To be recoverable, every hooked function in the chain
;*         must do exactly the following:
;*        
;*            1. Perform all necessary computation required by the new transform;
;*            2. If it fails for any reason, restore to old state and return
;*               error;
;*            3. Otherwise, make sure it can still recover to original state
;*               if the next function in chain fails;
;*            4. Call the next funcion in chain;
;*            5. If the call fails, goto step 2;
;*            6. Otherwise, commit all necessary changes and return success.
;*        
;*          Registers Destroyed:                
;*                AX,BX,CX,DX,ES        
;*
;* INPUT         = hdc     :DWORD
;*                 Flags   :DWORD
;*                 lpData  :PULONG
;*                 pddc    :PDDC
;*                 FunN    :DWORD  
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 for success  
;* RETURN-ERROR  = AX = 0     
;*
;**************************************************************************/

sBegin  Code
        assumes cs,Code

        check   NotifyTransformChange,<hdc,flCmd,pntd,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   NotifyTransformChange,<PUBLIC,FAR,NODATA>,<si>
        parmD   hdc
        parmD   Flags
        parmD   lpData
        parmD   hddc
        parmD   FunN
        localV  new_ddc_ptsCurPos,%(SIZE POINTS)
        localV  ptsPatOrg,%(size POINTS)
        localB  old_ddc_fb
cBegin
        assert  Flags.hi,E,0

        cld
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                        ; ds:si --> ddc
        mov     dx,si
        call    enter_driver
        njc     ntc_exit_no_lock                  ; DX:AX = 0 on error

;/*
;** we can skip all these if we are changing transform from unit to unit,
;*/

        mov     al,[si].ddc_fb
        mov     old_ddc_fb,al
        or      al,DDC_UNIT_XFORM
        cmp     Flags.lo,MATRIX_UNITS+MATRIX_SIMPLE
        je      @F
        and     al,not DDC_UNIT_XFORM
@@:
        mov     [si].ddc_fb,al                    
        or      [si].ddc_ca.ca_ba.ba_fb,BA_XFORM_CHANGE or BA_REREALIZE
        or      [si].ddc_pa.pa_ba.ba_fb,BA_XFORM_CHANGE or BA_REREALIZE
        or      [si].ddc_la.la_ba.ba_fb,BA_XFORM_CHANGE or BA_REREALIZE
        or      [si].ddc_ia.ia_ba.ba_fb,BA_XFORM_CHANGE or BA_REREALIZE
        or      [si].ddc_ma.ma_ba.ba_fb,BA_XFORM_CHANGE or BA_REREALIZE

;/*
;** update screen position
;** world position remain the same
;*/

update_screen_position:
        les     bx,[si].ddc_prddc
        assumes es,nothing
        CPUMode 386
        push    es:[bx].rddc_ptlWorldPos.ptl_y
        push    es:[bx].rddc_ptlWorldPos.ptl_x
        fw_zero <es>
        CPUMode 286
        mov     bx,sp
        farPtr  lp_point,ss,bx
        cCall   convert_world_screen,<lp_point,1> ; DS:SI = DDC
        pop     new_ddc_ptsCurPos.pts_x
        pop     bx
        pop     new_ddc_ptsCurPos.pts_y
        pop     bx
        assert  ax,E,cx
        jcxz    ntc_restore                       ; back up all changes

;/*
;** make sure pick window is valid in device coordinates
;*/

        cCall   recalc_correlate_rect
        jcxz    ntc_restore                       ; back up all changes

;/*
;** make sure pattern origin is valid in new coordinate space
;*/

        mov     ax,[si].ddc_pa.pa_ptsOrg.pts_x
        mov     ptsPatOrg.pts_x,ax
        mov     ax,[si].ddc_pa.pa_ptsOrg.pts_y
        mov     ptsPatOrg.pts_y,ax
        call    xform_pattern_origin
        or      ax,ax
        jz      ntc_restore_pattern

;/*
;** we call the next in chain only if we are sure we can do this transform
;*/

        cCall   pfnDefNotifyTransformChange,<hdc,Flags,lpData,hddc,FunN>
        or      ax,ax
        jnz     ntc_doit

;/*
;** something went wrong, we have to back up all changes
;*/

ntc_restore_pattern:
        mov     ax,ptsPatOrg.pts_x
        mov     [si].ddc_pa.pa_ptsOrg.pts_x,ax
        mov     ax,ptsPatOrg.pts_y
        mov     [si].ddc_pa.pa_ptsOrg.pts_y,ax

ntc_restore:
        ddc?    si
        mov     al,old_ddc_fb
        or      al,DDC_CORR_INV                   ; invalidate ddc_corr_rect
        mov     [si].ddc_fb,al                    ; restore flags
        xor     ax,ax
        jmp     short ntc_exit

;/*
;** everything is golden, complete the call
;*/

ntc_doit:
        or      [si].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
        les     si,[si].ddc_prddc
        assumes es,nothing
        rddc?   es,si
        CPUMode 386
        mov     ebx,new_ddc_ptsCurPos
        mov     dword ptr es:[si].rddc_ptsCurPos,ebx
        .errnz  (size POINTS)-4
        CPUMode 286
        assert  ax,E,1

ntc_exit:
        cwd
        call    leave_driver
ntc_exit_no_lock:
        fw_zero <es,cx>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = LockDevice
;*
;* DESCRIPTION   = 
;*
;*      This function is used to synchronize use and update of VisRegion.
;*      It allows all current and pending drawing to complete
;*      and blocks any further requests by other threads to draw.
;*     
;*      Upon exit, the only thread that is allowed to continue screen I/O
;*      is the one that acquires the lock.
;*     
;*      All screen I/O operations by other threads will be blocked until
;*      UnlockDevice is called.
;*     
;*      LockDevice and UnlockDevice are used mainly in the critical sections
;*      of visible region calculations.
;*     
;*      To prevent deadlock, it is guaranteed that no Death or Resurrection
;*      will be called by the window manager while the VisRegion is locked.
;*     
;*
;* INPUT         =
;* OUTPUT        =
;*
;* RETURN-NORMAL = AX = 1 for success  
;* RETURN-ERROR  = AX = 0              
;*
;* -----------------------------Pseudo-Code-------------------------------;
;*  BOOL FAR PASCAL LockDevice(hdc,FunN)
;*  {
;*    P(ScreenSem);
;*    return 1;
;*  }
;**************************************************************************/

        check   LockDevice,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   LockDevice,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   hddc
        parmD   FunN

cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      ld_exit_no_lock                   ; DX:AX = 0 on error

;/*
;** don't free DriverSem for now!!!
;*/

        mov     ax,1
        cwd
ld_exit_no_lock:
        fw_zero <es,cx>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = UnlockDevice
;*
;* DESCRIPTION   = 
;*
;*      This function is used to synchronize use and update of VisRegion.
;*      It allows all pending screen I/O operations blocked by LockDevice
;*      to continue.
;*     
;*      LockDevice and UnlockDevice are used mainly in the critical sections
;*      of visible region calculations.
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        check   UnlockDevice,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   UnlockDevice,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   hddc
        parmD   FunN

cBegin

        mov     ds,CodeData
        assumes ds,Data

;/*
;** free DriverSem for now!!!  see LockDevice
;*/
        call    leave_driver

        mov     ax,1
        cwd
        fw_zero <es,cx>

cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = Death      
;*
;* DESCRIPTION   = This function is used to provide notification of a screen group 
;*                 switch into another screen group.                               
;*                 
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 for success 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   Death,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   Death,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   hddc
        parmD   FunN

cBegin
        mov     ds,CodeData
        assumes ds,Data

ifdef FIREWALLS
        cmp     fGrimReaper,0
        je      not_dead_yet
        rip     text,<Death warmed over - Cannot kill me twice>
not_dead_yet:
endif
        cCall   far_physical_disable

        mov     ax,1
        cwd
        fw_zero <es,cx>

cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = Resurrection                
;*
;* DESCRIPTION   = This function is used to provide notification of a screen group
;*                 switch back from another screen group.                         
;*                 
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 if VRAM completely restored, 2 if not.
;* RETURN-ERROR  = AX = 0 unrecoverable error 
;*
;*                      -------Pseudo-Code-----
;* BOOL FAR PASCAL Resurrection(hdc,cbDirty,pbDirty,FunN)
;* {
;*   LockDevice();       // prevent screen I/O
;*   setup screen hardware;
;*   DeathFlag = 0;
;*   UnlockDevice();
;*   return 1;
;* }
;**************************************************************************/

        check   Resurrection,<hdc,cbDirty,pbDirty,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   Resurrection,<PUBLIC,FAR,NODATA>

        parmD   hdc
        parmD   cbDirty
        parmD   pbDirty
        parmD   hddc
        parmD   FunN

cBegin
        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jnc     @F

;/*
;** cannot recover from here!
;*/
        rip     text,<Resurrection: Oops! you live once only>
        mov     ax,PMERR_INV_HDC
        save_unrecoverable_code                   ; die in peace
        xor     ax,ax
        cwd
        jmp     res_exit_no_lock
@@:

;/*
;** prevent screen I/O
;*/

        check   LockDevice,<hdc,hddc,ulFunN>
        cCall   LockDevice,<hdc,hddc,GreLockDevice>
ifdef FIREWALLS
        cmp     ax,1
        je      lock_ok
        rip     text,<Error on acquiring/releasing a semaphore>
lock_ok:
endif

ifdef FIREWALLS
        cmp     fGrimReaper,-1                    ;-1 if we cannot write to screen
        je      am_dead
        rip     text,<Dawn of the Dead - Cannot ressurect the undead>
am_dead:
endif



;/*
;** Invalidate any pattern cache
;*/

        mov     idBrushCache.lo,PAT_CACHE_INVALID and 0FFFFh
        mov     idBrushCache.hi,PAT_CACHE_INVALID shr 16


;/*
;** initialize screen hardware
;*/

        push    bx                      ;SVGA force repaint for Video7 cards
        mov     bx,wSVGAtype            ;SVGA
        cmp     bx,VIDEO7_ADAPTER       ;SVGA
        jne     video7_bypass           ;SVGA
        mov     cbDirty.lo,-1           ;SVGA
        mov     cbDirty.hi,-1           ;SVGA

video7_bypass:                          ;SVGA
        pop     bx                      ;SVGA

        cCall   far_physical_enable,<0,cbDirty>
                                                  ;returns 0 if VRAM was restored
        push    ax                                ;save return code

        check   UnlockDevice,<hdc,hddc,ulFunN>
        cCall   UnlockDevice,<hdc,hddc,GreUnlockDevice>

ifdef FIREWALLS
        cmp     ax,1
        je      unlock_ok
        rip     text,<Error on acquiring/releasing a semaphore>
unlock_ok:
endif
        pop     ax                                ;get code from restore_textvram
        inc     ax                                ;return either 1 or 2

        mov     bx,wSVGAtype                      ;force repaint for some SVGA cards
        cmp     bx,VIDEO7_ADAPTER
        jne     resurrect_exit
        mov     ax,2

                                                  ;(2 implies we couldn't restore VRAM)
resurrect_exit:
        call    leave_driver
res_exit_no_lock:
        fw_zero <es,cx>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = GetDCOrigin
;*
;* DESCRIPTION   = Copies the DC origin from the DC to the given location.
;*
;* INPUT         = DWORD hdc  
;*                 DWORD *lpXY
;*                 DWORD pddc 
;*                 DWORD FunN 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  = 
;*
;**************************************************************************/

        check   GetDCOrigin,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetDCOrigin,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   lpXY
        parmD   hddc
        parmD   FunN
cBegin
        ddc?    hddc
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        call    enter_driver
        jc      gdco_exit_no_lock                 ; DX:AX = 0 on error

        les     di,lpXY                           ; point ES:DI to X and Y values
        assumes es,nothing
        cld
        CPUMode 386
        lgs     si,[si].ddc_prddc
        assumes gs,nothing
        lea     si,[si].rddc_ptsOrg
        .errnz  SIZE POINTL - 8
        lods    word ptr gs:[si]                 ; move X origin
        cwde
        stosd

        lods    word ptr gs:[si]                 ; move Y origin
        cwde
        stosd
        CPUMode 286

        mov     ax,1
        cwd
        call    leave_driver
gdco_exit_no_lock:
        fw_zero <es,cx>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSetDCOrigin 
;*
;* DESCRIPTION   = Sets the DDC origin of the specified device context.  Note that 
;*                 the device origin is 0,0 when the device context is created.    
;*                                                                                 
;*                 Note: DC origins at all saved levels of the DDC will be changed 
;*                       at restore time.                                          
;*                 
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,ES  
;*                 
;* INPUT         = hdc     :DWORD
;*                 lpXY    :DWORD
;*                 pddc    :DWORD
;*                 FunN    :DWORD
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 for success 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   DeviceSetDCOrigin,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceSetDCOrigin,<PUBLIC,FAR,NODATA>,<si>
        parmD   hdc
        parmD   lpXY
        parmD   hddc
        parmD   FunN
cBegin
        ddc?    hddc
        mov     ds,CodeData
        assumes ds,Data

;/*
;** This call only makes sense with the device locked, check it out!
;*/

        les     bx,lpXY
        assumes es,nothing

        mov     ax,es:[bx].ptl_x.lo
ifdef FIREWALLS
        cwd
        cmp     dx,es:[bx].ptl_x.hi
        je      @F
        rip     text,<SetDCOrigin - invalid integer>
@@:
endif
        xchg    cx,ax
        mov     ax,es:[bx].ptl_y.lo
ifdef FIREWALLS
        cwd
        cmp     dx,es:[bx].ptl_y.hi
        je      @F
        rip     text,<SetDCOrigin - invalid integer>
@@:
endif
        mov     bx,hddc.lo

;/*
;** Put new X origin into the ddc.  If delta X mod SIZE_PATTERN is 0,
;** the the pattern doesn't have to be rerealized.
;*/

        les     si,[bx].ddc_prddc
        assumes es,nothing
        rddc?   es,si
        xchg    cx,es:[si].rddc_ptsOrg.pts_x
        sub     cx,es:[si].rddc_ptsOrg.pts_x
        jz      sdco_done_x
        sub     es:[si].rddc_ptsCurPos.pts_x,cx     
        test    cx,SIZE_PATTERN-1                   ;Test modulo pattern size
        jz      sdco_done_x
        sub     [bx].ddc_pa.pa_ptsOrg.pts_x,cx
        or      [bx].ddc_pa.pa_ba.ba_fb,BA_REREALIZE
sdco_done_x:


;/*
;** The Y brush origin is always handled at output time, so we don't have
;** to realize the pattern.
;*/

        rddc?   es,si
        xchg    ax,es:[si].rddc_ptsOrg.pts_y
        sub     ax,es:[si].rddc_ptsOrg.pts_y
        sub     es:[si].rddc_ptsCurPos.pts_y,ax     
        sub     [bx].ddc_pa.pa_ptsOrg.pts_y,ax

;/*
;** invalidate ddc_corr_rect
;*/

        or      [bx].ddc_fb,DDC_CORR_INV
        mov     ax,1
        cwd
        fw_zero <es,cx>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceInvalidateVisRegion 
;*
;* DESCRIPTION   = When the display driver is entered for any calls requiring a       
;*                 valid  total clipping it must call pmwin to update vis region 
;*                 if the DC is dirty.                                                                          
;*                 This enables lazy vis region calculations in PM.                          
;*                                                                                           
;*                 This function must be called in a Lock/UnlockDevice bracket.              
;*
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,ES  
;*
;* INPUT         = lprghdc is a long pointer to an array of structures of the
;*                 form.
;*                         typedef struct {                                               
;*                             HDC   hDC;   ; a handle to a device context         
;*                             ULONG pddc;  ; unused by pmwin, filled in by engine.
;*                         } DC_BLOCK;                                                    
;*                                                                                        
;*                 Count is the number of elements in the array                           
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 for success    
;* RETURN-ERROR  = NONE
;*
;*                    ---------Pseudo-Code------
;* DeviceInvalidateVisRegion(hdc, count, lprghdc, pddc, FunN)
;* {
;*     /* must be serialized in pmwin */
;*     SemCheck(Device);
;*     for ( ; count; count--)
;*     {
;*       if (lprghdc[count].pddc.hi == HDDC_IDENT &&
;*           lprghdc[count].pddc->ddc_ident == DC_IDENTIFIER)
;*            lprghdc[count].pddc->ddc_flags |= DDC_DIRTY;
;*     }
;* }
;*
;**************************************************************************/

        check   DeviceInvalidateVisRegion,<hdc,civr,pivr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   DeviceInvalidateVisRegion,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   Count
        parmD   lprghdc
        parmD   hddc
        parmD   FunN
cBegin
        mov     ds,CodeData
        assumes ds,Data

;/*
;** This call only makes sense with the device locked, check it out!
;*/

ifdef FIREWALLS
        cCall   FSRSemCheck,<DataOFFSET semDriver>
        or      ax,dx
        jz      @F
        rip     text,<DeviceInvalidateVisRegion called without LockDevice>
@@:
endif

        assert  Count.hi,E,0
        mov     cx,Count.lo
        jcxz    divr_good_exit                     ; CX = count

        les     di,lprghdc                         ; ES:DI = lprghdc

divr_ddc_loop:

;/*
;** check the high word of hddc
;*/

        cmp     es:[di].ivr_hddc.hi,HDDC_IDENT
        jnz     divr_next_ddc

;/*
;** check out the ddc identifier
;*/

        mov     bx,es:[di].ivr_hddc.lo             ; BX = hDDC
        cmp     [bx].ddc_usId,DDC_IDENT
        jnz     divr_next_ddc                      ; not a DDC

;/*
;** mark the ddc as dirty
;*/

        or      [bx].ddc_fbAbove,DDC_DIRTY_VISRGN

divr_next_ddc:
        add     di,SIZE DC_BLOCK
        loop    divr_ddc_loop                      ; do next ddc

divr_good_exit:
        mov     ax,1
        cwd
cEnd

sEnd    Code

        end
