;*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 = BUILDSTR.ASM
;*
;* DESCRIPTIVE NAME = Build data on the stack for strblt
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/17/87
;*
;* DESCRIPTION  This module contains the strblt functions which build  
;*              up data on the stack for the actual output routines    
;*
;* FUNCTIONS    build_string
;*              real_build_string
;*              non_justified_text
;*              justified_text
;*              worst_case
;*              abc_case
;*              pad_left_hand_side
;*              pad_right_hand_side
;*              process_stack_data
;*              set_ega_opaque_mode
;*              prepare_for_overlap
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/17/87                     Written by Walt Moore
;*
;*****************************************************************************/

        .xlist
        include cmacros.inc
INCL_GRE_CLIP           equ                      1
INCL_FONTFILEFORMAT     equ                      1
        include pmgre.inc
        include driver.inc
        include egafam.inc
        include egamemf.inc
        include strblt.inc
        include fontseg.inc
        .list


sBegin  Code
        assumes cs,Code
        assumes ss,ss_variables

        externNP preset_pro_text
        externNP worst_case_ext
        externNP comp_byte_interval
        externNP output_o_rect
page

;/***************************************************************************
;*
;* FUNCTION NAME = build_string  
;*
;* DESCRIPTION   = build_string builds up data on the stack consisting of character
;*                 offsets and widths, then invokes the routine which processes    
;*                 this data.                                                      
;*
;*                 Registers Preserved:                
;*                       BP                            
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS 
;*
;* INPUT         = stack frame as per strblt 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing
        assumes ss,ss_variables

define_frame build_string                         ;Define strblt's frame

cBegin  <nogen>
cEnd    <nogen>


real_build_string proc near

        mov     ax,SS_VARIABLES_LEN+STACK_SLOP ; Don't let stack trash our vars.
        mov     min_stack,ax
        mov     ax,text_bbox.rcs_pts1.pts_x ;Make text bbox a null interval
        mov     text_bbox.rcs_pts2.pts_x,ax ;  We'll grow it as we progress
        mov     current_lhs,ax                    ;Need to init this for interval calc

        mov     al,accel                          ;Save the actual state of the
        mov     bl,al                             ;  IS_OPAQUE flag since the
        and     al,IS_OPAQUE                      ;  worst case code may alter
        or      wc_flags,al                       ;  it
        mov     ah,excel                          ;Only set text visible once a string
        and     ah,not TEXT_VISIBLE              ; is actually displayed
        mov     excel,ah

        mov     cx,CodeOFFSET non_justified_text
        test    bl,HAVE_WIDTH_VECT or ABC_FONT or HAVE_CHAR_EXTRA
        jz      build_have_proc
        mov     cx,CodeOFFSET justified_text
        test    bl,HAVE_WIDTH_VECT or ABC_FONT
        jz      build_have_proc
        test    bl,IS_OPAQUE                      ;If transparent mode, then no
        jz      build_worst_ok                    ;  special work is required
        test    wc_flags,STEPPED_BACK            ;If we don't step backwards, no
        jz      build_worst_ok                    ;  special work is required
        call    prepare_for_overlap              ;Massive preprocessing required

build_worst_ok:
        mov     bl,accel
        mov     ah,excel
        mov     cx,CodeOFFSET worst_case
        test    bl,ABC_FONT
        jz      build_have_proc
        mov     cx,CodeOFFSET abc_case
        or      wc_flags,WC_FIRST                 ;Very frist call is special

build_have_proc:
        mov     build_proc,cx                     ;Save build routine address
        call    preset_pro_text                   ;Set frame/ss: locations as needed

build_restart:
        mov     clear_stack,sp                    ;Used to clean the stack on exit
        mov     ax,sp                             ;Save buffer start pointer
        dec     ax
        dec     ax
        mov     buffer,ax

;/*
;**       The routines which push text onto the stack expect the
;**       following registers to be set on entry:
;**
;**               DS:SI --> current character in the string
;**               ES:    =  font segment
;**               AL     =  excel flags
;**               AH     =  accel flags
;**               CX     =  number of characters in the string
;**               DI     =  current X position (and therefore starting x)
;*/

        lds     si,lp_string
        assumes ds,nothing
        mov     es,selFont
        assumes es,FontSeg
        mov     al,excel
        mov     ah,accel
        mov     cx,count
        mov     di,x
        jmp     build_proc

build_ret_addr:                                   ;build routines return here
        mov     count,cx                          ;Save count
        mov     x,ax                              ;Save next char's start
        mov     off_lp_string,si                  ;Save next character
        call    pad_right_hand_side               ;Fill to byte boundary if possible
        mov     current_rhs,di                    ;Save rhs
        mov     bx,di                             ;Compute the interval data
        mov     dx,current_lhs
        call    comp_byte_interval
        jc      build_all_done                    ;If nothing shows, we're done
        mov     left_clip_mask,al
        mov     right_clip_mask,ah
        mov     inner_byte_count,si
        mov     scan_start,di
        call    process_stack_data                ;Display the string
        mov     sp,clear_stack

        or      excel,TEXT_VISIBLE                ;Show something was displayed

;/*
;**       If there is an opaquing rectangle, we must update the text
;**       bounding box so that it won't overwrite the text we just
;**       displayed when the rectangle is output.  IN transparent mode,
;**       OPAQUE_RECT would have been cleared after the rectangle was
;**       drawn and before we were called.
;**
;*/

        test    excel,OPAQUE_RECT
        jz      build_no_o_rect
        mov     ax,current_lhs
        mov     bx,text_bbox.rcs_pts1.pts_x
        smin_ax bx
        mov     text_bbox.rcs_pts1.pts_x,ax
        mov     ax,current_rhs
        mov     bx,text_bbox.rcs_pts2.pts_x
        smax_ax bx
        mov     text_bbox.rcs_pts2.pts_x,ax

build_no_o_rect:
        mov     cx,count                          
        jcxz    build_restore_opaque              


;*/
;**     Prepare for the next string.  If in opaque mode, the
;**     CLIPPED_LEFT flag will have to be set so that we don't
;**     try padding the lhs.  If in transparent mode, because
;**     of stepping backwards, we might actually be clipped
;**     anyway, so we'll have to test for this also.
;**
;**     FIRST_IN_PREV must be cleared.           It will be set if the
;**     clipping code determines it needs to be.
;**
;*/

        mov     bl,excel                          ;Will be changing flags in here
        and     bl,not (CLIPPED_LEFT+FIRST_IN_PREV)
        mov     di,x
        mov     ax,di                             ;Assume start will be current_lhs
        test    accel,IS_OPAQUE                  ;When opaque, must clip on
        jnz     build_clip_next_time             ;  a restart
        cmp     di,clip.rcs_pts1.pts_x
        jge     build_no_clip_next_time

build_clip_next_time:
        or      bl,CLIPPED_LEFT                  ;Clipping is required
        mov     ax,clip.rcs_pts1.pts_x           ;  and clip.rcs_pts1.pts_x for clipping check
        smax_ax di                               ;  (but only if start X > old clip
        mov     clip.rcs_pts1.pts_x,ax           ;   lhs)

build_no_clip_next_time:
        mov     excel,bl
        mov     current_lhs,ax                    ;Need to update lhs for interval calc
        jmp     build_restart                     ;Try next part of the string

build_all_done:
        mov     sp,clear_stack

build_restore_opaque:
        mov     al,wc_flags
        test    al,WC_SET_LR                      ;If we stepped backwards, we'll
        jz      build_really_done                 ;  have to restore the real lhs
        mov     bx,wc_opaque_lhs                  ;  and rhs incase we have an
        mov     text_bbox.rcs_pts1.pts_x,bx       ;  opaque rectangle
        mov     bx,wc_opaque_rhs
        mov     text_bbox.rcs_pts2.pts_x,bx

build_really_done:
        and     al,IS_OPAQUE                      ;Restore IS_OPAQUE incase worst_case
        or      accel,al                          ;  code cleared it, else the opaque
        ret                                       ;  rectangle may overwrite our text

real_build_string endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  non_justified_text    
;*
;* DESCRIPTION   = This is the simple case for proportional text.  No justification,   
;*                 no width vector.  Just run the string.  If we run out of stack      
;*                 space, then that portion of the string which fits will be 
;*                 displayed and we'll restart again after that.
;*
;*                 spcl - simple, proportional, clip lhs  
;*                 sfcl - simple, fixed pitch,  clip lhs  
;*                 sc   - simple, clip rhs                
;*
;*                 Registers Preserved:                
;*                       BP                            
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS 
;*
;* INPUT         = DS:SI --> current character in the string               
;*                 ES:    =  font segment                                  
;*                 AL     =  excel flags                                   
;*                 AH     =  accel flags                                   
;*                 CX     =  number of characters in the string            
;*                 DI     =  current X position (and therefore starting x) 
;*                 stack frame as per strblt                               
;*
;* OUTPUT        = DS:SI --> current character in the string     
;*                 ES:    =  font segment                        
;*                 CX     =  number of characters left in string 
;*                 DI     =  string rhs                          
;*                 AX     =  next character's X                  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

        public  non_justified_text
non_justified_text proc near

        test    al,CLIPPED_LEFT
        jz      sc_no_left_clipping              ;No clipping needed on lhs
        mov     dx,clip.rcs_pts1.pts_x           ;Characters become visible here
        test    ah,FIXED_PITCH
        jz      spcl_next_char                    ;Proportional font


;/*
;**       Fixed pitch, no justification, left hand clipping
;*/

        mov     bx,lfd.font_width                 ;Fixed pitch font.

sfcl_next_char:
        add     di,bx                             ;Does this character become visible?
        cmp     dx,di                             ;DX is clip.rcs_pts1.pts_x
        jl      sfcl_current_is_visible           ;This char is visible
        inc     si
        inc     si
        loop    sfcl_next_char                    ;See if next character

sfcl_no_chars_visible:
        jmp     build_ret_addr                    ;Return to caller

sfcl_current_is_visible:
        sub     di,bx                             ;Restore staring address of character
                                                  ;  and just fall into the proportional
                                                  ;  code which will handle everything

;/*
;**       Proportional, no justification, left hand clipping
;*/

spcl_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        add     di,ax                             ;0 width chars won't change x position
        cmp     dx,di                             ;DX is clip.rcs_pts1.pts_x
        jl      spcl_current_is_visible           ;This char is visible

spcl_see_if_next:
        loop    spcl_next_char                    ;See if next character
        jmp     build_ret_addr                    ;Return to caller

spcl_current_is_visible:
        sub     di,ax                             ;Restore starting x of character
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top             ;Adjust pointer for any clipping


;/*
;**       Instead of incrementing the current position by 8 and
;**       having to recover the real current position, we just
;**       slide the clip region left.  It has the same effect.
;*/

        sub     dx,di                             ;Compute bits until we're visible
        je      spcl_save_first                   ;Starts on clip edge
        sub     dx,8                              ;Is current byte visible?
        jl      spcl_have_vis_start               ;  Yes

spcl_step_clipped_char:
        sub     ax,8                              ;Shorten the width of the character
        add     di,8                              ;Move current position right
        add     bx,lfd.font_height                ;Move to next column of character
        sub     dx,8                              ;Is current byte visible?
        jge     spcl_step_clipped_char            ;  No


;/*
;**        If the lhs of the clip region and the starting X of the
;**        character are in different bytes, then the FIRST_IN_PREV
;**        flag must be set.  Only a clipped character can set this
;**        flag.
;*/

spcl_have_vis_start:
        mov     dx,clip.rcs_pts1.pts_x
        xor     dx,di
        and     dx,not 7
        jz      spcl_save_first                  ;In same byte
        or      excel,FIRST_IN_PREV


;/*
;**        We have the start of the first character which is visible
;**        Determine which loop (clipped/non-clipped) will process it.
;**        We let the routine we're about to call push the character
;**        since it will handle both right clipping (if needed) and
;**        fat characters.
;/*

spcl_save_first:
        jmp     short scc_clip_enters_here


;/*
;**       There was no left hand clipping.  Whenever this is the case,
;**       we want to try and pad the lhs out to a byte boundary so that
;**       full byte code can be used.
;*/

sc_no_left_clipping:
        call    pad_left_hand_side               ;Might be able to pad lhs


;/*
;**       scc - simple case, rhs clipping.
;**
;**       This loop is used when it is possible for the character
;**       to be clipped on the rhs.  lhs clipping has already
;**       been performed.  There is no justification.
;**
;**       Currently:
;**               DS:SI --> current character in the string
;**               ES:    =  font segment
;**               DI     =  current X position
;**               CX     =  number of bytes left in the string
;*/

scc_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        or      ax,ax                             ;If width is 0, ignore character
        jz      scc_see_if_next
        add     bx,amt_clipped_on_top             ;Adjust pointer for any clipping

scc_clip_enters_here:
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     scc_char_is_clipped               ;Clipped (or first pixel of next is)

scc_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        cmp     ax,8                              ;If character is less than 8 bits
        jbe     scc_width_ok                      ;  wide, push it's data
        mov     dl,8                              ;Need 8 for size in DL

scc_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        add     bx,lfd.font_height                ;  of the remaining width
        cmp     ax,8
        ja      scc_still_wide

scc_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits
        cmp     sp,min_stack                      ;Stack compare must be unsigned
        jb      scc_restart                       ;Not enough stack for another character

scc_see_if_next:
        loop    scc_next_char                     ;Until all characters pushed
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr


;/*
;**        This character is either clipped, or it's last pixel is
;**        the last pixel which will fit within the clipping rhs.
;**        Adjust it's width so it fits, set the remaining character
;**        count to 1 so the loop will terminate, and reenter the
;**        code where we came from.
;/*

scc_char_is_clipped:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        mov     cx,1                              ;Show this as last character
        jmp     scc_been_clipped                  ;Finish here


;/*
;**       There is no more space on the stack to build characters.
;**       If this was the last character, then don't bother with the
;**       restart.
;*/

scc_restart:
        dec     cx                                ;Adjust count for char just pushed
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr

non_justified_text endp
page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  justified_text
;*
;* DESCRIPTION   = This is the justification case for text, when positive character 
;*                 extra is given.  If we run out of stack space, then that portion 
;*                 of the string which fits will be displayed, and we'll restart    
;*                 again after that.                                                
;*                                                                                  
;*                 jc  - justify clipped                                            
;*                 jcl - justify clip left                                          
;*
;*                 Registers Preserved:                
;*                       BP                            
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS 
;*
;* INPUT         = DS:SI --> current character in the string              
;*                 ES:    =  font segment                                 
;*                 AL     =  excel flags                                  
;*                 AH     =  accel flags                                  
;*                 CX     =  number of characters in the string           
;*                 DI     =  current X position (and therefore starting x)
;*                 stack frame as per strblt                              
;*
;* OUTPUT        = DS:SI --> current character in the string     
;*                 ES:    =  font segment                        
;*                 CX     =  number of characters left in string 
;*                 DI     =  string rhs                          
;*                 AX     =  next character's X                  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

        public  justified_text
justified_text  proc    near

        test    excel,CLIPPED_LEFT
        jnz     jcl_next_char                     ;Clipping needed
        call    pad_left_hand_side                ;Might be able to pad lhs
        jmp     short jc_next_char

jcl_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        mov     dx,char_extra

jcl_have_width:
        add     di,ax                             ;DI = next chars starting X
        cmp     clip.rcs_pts1.pts_x,di
        jl      jcl_current_is_visible            ;This char is visible
        add     di,dx
        cmp     clip.rcs_pts1.pts_x,di
        jl      jcl_dummy_is_visible              ;Dummy is first visible character

jcl_see_if_next:
        loop    jcl_next_char                     ;See if next character
        jmp     build_ret_addr                    ;Return to caller


;/*
;**       The dummy character is the first character which became
;**       visible.  Just set the starting X to clip.rcs_pts1.pts_x, and shorten
;**       the width of the dummy character appropriately.
;*/

jcl_dummy_is_visible:
        mov     dx,di
        mov     di,clip.rcs_pts1.pts_x            ;Starting X is clip.rcs_pts1.pts_x
        sub     dx,di                             ;DX is # pixels in dummy
        xor     ax,ax                             ;Show no real character
        jmp     short jcl_all_done


;/*
;**       We just encountered the first character which will be visible
;**       Clip it on the lhs as needed.
;*/

jcl_current_is_visible:
        sub     di,ax                             ;Restore starting x of character
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top             ;Adjust pointer for any clipping


;/*
;**       Instead of incrementing the current position by 8 and
;**       having to recover the real current position, we just
;**       slide the clip region left.  It has the same effect.
;*/

        push    dx                                ;Save extra pixels
        mov     dx,clip.rcs_pts1.pts_x
        sub     dx,di                             ;Compute bits until we're visible
        je      jcl_save_first                    ;Starts on clip edge
        sub     dx,8                              ;Is current byte visible?
        jl      jcl_have_vis_start                ;  Yes

jcl_step_clipped_char:
        sub     ax,8                              ;Shorten the width of the character
        add     di,8                              ;Move current position right
        add     bx,lfd.font_height                ;Move to next column of character
        sub     dx,8                              ;Is current byte visible?
        jge     jcl_step_clipped_char             ;  No

;/*
;**        If the lhs of the clip region and the starting X of the
;**        character are in different bytes, then the FIRST_IN_PREV
;**        flag must be set.  Only a clipped character can set this
;**        flag.
;*/

jcl_have_vis_start:
        mov     dx,clip.rcs_pts1.pts_x
        xor     dx,di
        and     dx,not 7
        jz      jcl_save_first                    ;In same byte
        or      excel,FIRST_IN_PREV

;/*
;**        We have the start of the first character which is visible
;**        We let the routine we're about to call push the character
;**        since it will handle both right clipping (if needed) and
;**        fat characters.
;*/


jcl_save_first:
        pop     dx                                ;Restore extra pixels

jcl_all_done:
        jmp     short jc_clip_enters_here

;/*
;**       jc - justified with clipping
;**
;**       This loop is used for justified text.  It will perform
;**       rhs clipping.  lhs clipping has already been performed.
;**
;**       Currently:
;**               DS:SI --> current character in the string
;**               ES:    =  font segment
;**               DI     =  current X position
;**               CX     =  number of bytes left in the string
;*/

jc_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        mov     dx,char_extra

jc_have_width:
        or      ax,ax
        jz      jc_check_dummy                    ;If width is 0, might still have dummy
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top             ;Adjust pointer for any clipping

jc_clip_enters_here:
        mov     num_null_pixels,dx                ;Save # null pixels
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     jc_char_is_clipped                ;Clipped (or first pixel of next is)

jc_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If character is less than 8 bits
        jbe     jc_width_ok                       ;  wide, push its data

jc_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        add     bx,lfd.font_height                ;  of the remaining width
        cmp     ax,8
        ja      jc_still_wide

jc_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits
        mov     dx,num_null_pixels

jc_check_dummy:
        or      dx,dx
        jz      jc_see_if_next                    ;No pixels for justification
        xchg    ax,dx                             ;Set ax = number of pixels to fill
        mov     bx,null_char_offset
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     jc_dummy_is_clipped               ;Clipped (or first pixel of next is)

jc_dummys_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If dummy is less than 8 bits
        jbe     jc_dummy_width_ok                 ;  wide, push it's data

jc_dummy_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        cmp     ax,8
        ja      jc_dummy_still_wide

jc_dummy_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits

jc_see_if_next:
        cmp     sp,min_stack                      ;Stack compare must be unsigned
        jb      jc_restart                        ;Not enough stack for another character
        dec     cx
        jle     jc_all_done
        jmp     jc_next_char                      ;Until all characters pushed

jc_all_done:
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr


;/*
;**       This character is either clipped, or it's last pixel is
;**       the last pixel which will fit within the clipping rhs.
;**       Adjust it's width so it fits, set the remaining character
;**       count to 1 so the loop will terminate, and reenter the
;**       code where we came from.
;**
;**       Might as well set num_null_pixels to zero to skip that code.
;*/

jc_char_is_clipped:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        xor     cx,cx                             ;Dont't want any extra pixels
        mov     num_null_pixels,cx
        inc     cx                                ;Show this as last character
        jmp     jc_been_clipped                   ;Finish here


;/*
;**       The dummy is either clipped, or it's last pixel is
;**       the last pixel which will fit within the clipping rhs.
;**       Adjust it's width so it fits, set the remaining character
;**       count to 1 so the loop will terminate, and reenter the
;**       code where we came from.
;*/

jc_dummy_is_clipped:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        mov     cx,1                              ;Show this as last character
        jmp     jc_dummys_been_clipped            ;Finish here


;/*
;**       These is no more space on the stack to build characters.
;**       If this was the last character, then don't bother with the
;**       restart.
;*/

jc_restart:
        dec     cx                                ;Adjust count for char just pushed
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr

justified_text  endp

        page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  worst_case   
;*
;* DESCRIPTION   = This is the worst case text code, where there is some combination 
;*                 of the width vector and character extra.                          
;*                                                                                   
;*                 If we step backwards or we run out of stack space, then that      
;*                 whatever has been built up on the stack will be displayed, and    
;*                 we'll restart again after that.                                   
;*                                                                                   
;*                 wcc - worse case clipped                                          
;*                 wccl - worse case clip left                                       
;*
;*                 Registers Preserved:                
;*                       BP                            
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS 
;*
;* INPUT         = DS:SI --> current character in the string              
;*                 ES:    =  font segment                                 
;*                 AL     =  excel flags                                  
;*                 AH     =  accel flags                                  
;*                 CX     =  number of characters in the string           
;*                 DI     =  current X position (and therefore starting x)
;*                 stack frame as per strblt                              
;*
;* OUTPUT        = DS:SI --> current character in the string    
;*                 ES:    =  font segment                       
;*                 CX     =  number of characters left in string
;*                 DI     =  string rhs                         
;*                 AX     =  next character's X                 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

        public  worst_case
worst_case      proc near

        test    excel,CLIPPED_LEFT
        jnz     wccl_next_char                    ;Clipping needed
        call    pad_left_hand_side                ;Might be able to pad lhs
        jmp     wcc_next_char


;/*
;**       This is the start of the real loop for left hand clipping.
;*/

wccl_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        push    bx                                ;Must save character index
        les     bx,lp_dx
        assumes es,nothing
        mov     dx,word ptr es:[bx]               ;DX is delta to next char's start
        inc     bx
        inc     bx
        mov     lp_dx.off,bx
        mov     es,selFont
        assumes es,FontSeg
        sub     dx,ax                             ;Compute adjustment to width


;/*
;**     DX contains any adjustment to the next characters starting
;**     position.  If this number is negative, then we'll be stepping
;**     over the previous character.
;**
;**     We don't allow a character to start before the previous
;**     character.  We'll have to enforce this at this point by
;**     making sure that any negative adjustment is less than or
;**     equal to the character width.
;*/

wccl_have_width:
        or      dx,dx
        jge     wccl_adjustment_ok
        add     dx,ax                             ;Don't allow the backwards step
        sbb     bx,bx                             ;  to go beyond the start of this
        and     dx,bx                             ;  character
        sub     dx,ax

wccl_adjustment_ok:
        pop     bx                                ;Restore char index
        add     ax,di                             ;AX = rhs of character
        cmp     clip.rcs_pts1.pts_x,ax
        jl      wccl_current_is_visible           ;Some part of char is visible


;/*
;**     If the adjustment for the character width is greater than the
;**     actual width of the character, then it is possible that the
;**     dummy pixels could become visible.  If the adjustment for the
;**     character width is less than the actual character width, then
;**     the dummy pixel (negative dummy pixels?) cannot become visible.
;*/

        add     ax,dx                             ;Next char starts at AX
        mov     di,clip.rcs_pts1.pts_x
        cmp     di,ax
        jl      wccl_dummy_is_visible             ;Some part of dummy char became visible
        xchg    di,ax                             ;Set start of next character

wccl_see_if_next:
        loop    wccl_next_char                    ;See if next character
        jmp     build_ret_addr                    ;Return to caller



;/*
;**       The dummy character is the first character which became
;**       visible.  Just set the starting X to clip.rcs_pts1.pts_x, and shorten
;**       the width of the dummy character appropriately.
;*/

wccl_dummy_is_visible:
        xchg    ax,dx                             ;Set DX = # pixels in dummy
        sub     dx,di
        xor     ax,ax                             ;Show no real character
        jmp     short wccl_all_done


;/*
;**     So here we are, we have a character which will become visible,
;**     and possibly have some adjustment to the character.
;**
;**     Our registers currently contain:
;**
;**             AX = rhs of character
;**             BX = index into offset/width table
;**             CX = # of characters left in the string
;**             DX = # of extra pixels (zero or positive)
;**             DI = starting X offset
;**             ES = FontSeg
;**             DS:SI --> string
;*/


wccl_current_is_visible:
        sub     ax,di                            ;Restore width of the character
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top            ;Adjust pointer for any clipping


;/
;**     Instead of incrementing the current position by 8 and
;**     having to recover the real current position, we just
;**     slide the clip region left.  It has the same effect.
;/*

        push    dx                                ;Save extra pixels to be added
        mov     dx,clip.rcs_pts1.pts_x
        sub     dx,di                             ;Compute bits until we're visible
        je      wccl_save_first                   ;Starts on clip edge
        sub     dx,8                              ;Is current byte visible?
        jl      wccl_have_vis_start               ;  Yes

wccl_step_clipped_char:
        sub     ax,8                              ;Shorten the width of the character
        add     di,8                              ;Move current position right
        add     bx,lfd.font_height                ;Move to next column of character
        sub     dx,8                              ;Is current byte visible?
        jge     wccl_step_clipped_char            ;  No


;/*
;**     If the lhs of the clip region and the starting X of the
;**     character are in different bytes, then the FIRST_IN_PREV
;**     flag must be set.  Only a clipped character can set this
;**     flag.
;*/

wccl_have_vis_start:
        mov     dx,clip.rcs_pts1.pts_x
        xor     dx,di
        and     dx,not 7
        jz      wccl_save_first                  ;In same byte
        or      excel,FIRST_IN_PREV


;/*
;**     We have the start of the first character which is visible.
;**     We let the routine we're about to call push the character
;**     since it will handle both right clipping (if needed) and
;**     fat characters.
;*/

wccl_save_first:
        pop     dx                                ;Restore extra pixels

wccl_all_done:
        jmp     short wcc_clip_enters_here


;/*
;**     wcc - worse case, with rhs clipping
;**
;**     Currently:
;**             DS:SI --> current character in the string
;**             ES:    =  font segment
;**             DI     =  current X position
;**             CX     =  number of bytes left in the string
;*/

wcc_next_char:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        mov     ax,fsCharOffset[bx].fe_width
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top            ;Adjust pointer for any clipping
        push    bx
        les     bx,lp_dx
        assumes es,nothing
        mov     dx,word ptr es:[bx]              ;DX is delta to next char's start
        inc     bx
        inc     bx
        mov     lp_dx.off,bx
        mov     es,selFont
        assumes es,FontSeg
        sub     dx,ax                             ;Compute adjustment to width

;/*
;**     DX contains any adjustment to the next characters starting
;**     position.  If this number is negative, then we'll be stepping
;**     over the previous character.
;**
;**     We don't allow a character to start before the previous
;**     character.  We'll have to enforce this at this point by
;**     making sure that any negative adjustment is less than or
;**     equal to the character width.
;*/

wcc_have_width:
        or      dx,dx
        jge     wcc_adj_is_ok
        add     dx,ax                             ;Don't allow the backwards step
        sbb     bx,bx                             ;  to go beyond the start of this
        and     dx,bx                             ;  character
        sub     dx,ax

wcc_adj_is_ok:
        pop     bx                                ;Restore bits offset

wcc_clip_enters_here:
        or      ax,ax                             ;If character width is 0,
        jz      wcc_check_dummy                   ;  might still have dummy char
        or      dx,dx                             ;Any adjustment to the width?
        jle     wcc_have_adj_width                ;No extra pixels to add
        push    bx
        mov     bx,ax                             ;  into the empty space of the
        neg     ax                                ;  character
        and     ax,7                              ;AX = # extra pixels which will fit
        jz      wcc_have_entire_width             ;None will fit
        cmp     ax,dx
        jl      wcc_have_what_fits                ;Some extra pixels will not fit
        mov     ax,dx                             ;All pixels will fit, make DX = 0

wcc_have_what_fits:
        sub     dx,ax                             ;DX = extra for the dummy character

wcc_have_entire_width:
        add     ax,bx                             ;Set number of pixels to use in char
        pop     bx

wcc_have_adj_width:
        mov     num_null_pixels,dx                ;Save number of dummy pixels
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     wcc_char_is_clipped               ;Clipped (or first pixel of next is)

wcc_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If character is less than 8 bits
        jbe     wcc_width_ok                      ;  wide, push it's data

wcc_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        add     bx,lfd.font_height                ;  of the remaining width
        cmp     ax,8
        ja      wcc_still_wide

wcc_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits
        mov     dx,num_null_pixels

wcc_check_dummy:
        xchg    ax,dx                             ;Just incase we go backwards
        or      ax,ax
        jz      wcc_see_if_next                   ;No pixels for justification
        jl      wcc_going_back
        mov     bx,null_char_offset
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     wcc_dummy_is_clipped              ;Clipped (or first pixel of next is)

wcc_dummys_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If dummy is less than 8 bits
        jbe     wcc_dummy_width_ok                ;  wide, push it's data

wcc_dummy_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        cmp     ax,8
        ja      wcc_dummy_still_wide

wcc_dummy_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits

wcc_see_if_next:
        cmp     sp,min_stack                      ;Stack compare must be unsigned
        jb      wcc_restart                       ;Not enough stack for another character
        dec     cx
        jle     wcc_all_done
        jmp     wcc_next_char                     ;Until all characters pushed

wcc_all_done:
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr



;/*
;**       The dummy is either clipped, or it's last pixel is
;**       the last pixel which will fit within the clipping rhs.
;**       Adjust it's width so it fits, set the remaining character
;**       count to 1 so the loop will terminate, and reenter the
;**       code where we came from.
;**
;**       If the width adjustment was negative, we would never have
;**       reached this code, so ignore any restart.
;*/

wcc_dummy_is_clipped:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        mov     cx,1                              ;Show this as last character
        jmp     wcc_dummys_been_clipped           ;Finish here



;/*
;**     This character is either clipped, or it's last pixel is
;**     the last pixel which will fit within the clipping rhs.
;**
;**     If there is a  negative adjustment to the width of the
;**     character, it is possible that the next character could
;**     be partially visible.  We'll have set up for a restart
;**     if this is the case.
;**
;**     If this is the last character of the string, then there
;**     is no problem
;**
;**     If no negative adjustment, adjust it's width so it fits,
;**     set the remaining character count to 1 so the loop will
;**     terminate, and reenter the code where we came from.
;*/

wcc_char_is_clipped:

        push    dx                                ;If num_null_pixels < 0, then
        mov     dx,num_null_pixels                ;  a restart might be possible
        or      dx,dx
        jl      wcc_might_need_restart            ;Might need a restart

wcc_clipped_no_restart:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        xor     cx,cx                             ;Don't want any extra pixels
        mov     num_null_pixels,cx
        inc     cx                                ;Show this as last character
        pop     dx
        jmp     wcc_been_clipped                  ;Finish here

;/*
;**       Might be looking a restart in the face.  Compute where the
;**       next character would start, and if it is to the left of
;**       clip.rcs_pts2.pts_x, then a restart is needed.
;*/

wcc_might_need_restart:
        cmp     cx,1                              ;If last character
        jle     wcc_clipped_no_restart            ;  then no restart needed
        add     dx,di                             ;Compute next starting x
        sub     dx,clip.rcs_pts2.pts_x
        jge     wcc_clipped_no_restart            ;Rest of string is clipped


;/*
;**        Will have to force a restart for the next character.  We
;**        can do this by computing the number of pixels between where
;**        where the next character starts and clip.rcs_pts2.pts_x.  This negative
;**        number will be stuffed into num_null_pixels, so when we reenter
;**        the main loop, we'll force a restart after pushing the character
;**     data
;/*

        mov     num_null_pixels,dx
        mov     dx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,dx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,dx                             ;Set new rhs
        pop     dx
        jmp     wcc_been_clipped                  ;Finish here


;/*
;**        I have the unfortunate task of informing you that the next
;**        character will start somewhere in the middle of the current
;**        character.  If this is the last character of the string,
;**        then nothing need be done.  If this isn't the last character,
;**        then a restart will be needed.
;/*

wcc_going_back:
        add     ax,di                             ;Set position of next character
        dec     cx                                ;Adjust count for char just pushed
        jmp     build_ret_addr



;/*
;**       Out of stack space.  Set up for a restart.
;*/

wcc_restart:
        mov     ax,di
        dec     cx                                ;Adjust count for char just pushed
        jmp     build_ret_addr

worst_case      endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  abc_case
;*
;* DESCRIPTION   = This is the abc spaced font code                                
;*                                                                                 
;*                 If we step backwards or we run out of stack space, then that    
;*                 whatever has been built up on the stack will be displayed, and  
;*                 we'll restart again after that.                                 
;*                                                                                 
;*                 abc - abc clipped                                               
;*                 abcl - abc clip left                                            
;*
;*                 Registers Preserved:                
;*                       BP                            
;*                 Registers Destroyed:                
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS 
;*
;* INPUT         = DS:SI --> current character in the string              
;*                 ES:    =  font segment                                 
;*                 AL     =  excel flags                                  
;*                 AH     =  accel flags                                  
;*                 CX     =  number of characters in the string           
;*                 DI     =  current X position (and therefore starting x)
;*                 stack frame as per strblt                              
;*
;* OUTPUT        = DS:SI --> current character in the string     
;*                 ES:    =  font segment                        
;*                 CX     =  number of characters left in string 
;*                 DI     =  string rhs                          
;*                 AX     =  next character's X                  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

        public  abc_case
abc_case        proc near

;/*
;**  If this is the very first call to this routine, we'll have to
;**  process any positive "a" space by faking up a dummy character
;**  for any positive "a" space.  If it isn't the very first call,
;**  we fake a real dummy char of 0 width (its 3:00 am).
;*/

        test    wc_flags,WC_FIRST
        jz      abc_not_first_time
        mov     bx,[si]                           ;Get "a" space for this
        imul    bx,(size ABC_FONT_ENTRIES)
        mov     dx,fsCharOffset[bx].abc_a_space
        or      dx,dx
        jns     abc_special_dummy_needed          ;Positive, must deal with it
abc_not_first_time:
        xor     dx,dx                             ;No dummy needed
abc_special_dummy_needed:
        and     wc_flags,not WC_FIRST
        test    al,CLIPPED_LEFT
        mov     ax,0                              ;Preseve flags
        jnz     abcl_very_first_enters_here       ;Clipping needed
        mov     num_null_pixels,dx                ;Cannot push!!
        call    pad_left_hand_side                ;Might be able to pad lhs
        mov     dx,num_null_pixels                ;Dummy >= zero
        xor     ax,ax                             ;No real width
        jmp     abc_clip_enters_here


;/*
;**       This is the start of the real loop for left hand clipping.
;*/

        public  abcl_next_char
abcl_next_char:
        xor     dx,dx                             ;Zero extra pels so far
        lodsw                                     ;Get this char's offset
        add     ax,ax                             ;*2
        mov     bx,ax
        add     ax,ax                             ;*4
        add     ax,ax                             ;*8
        add     bx,ax                             ;*10
        .errnz  size ABC_FONT_ENTRIES - 10
        dec     cx                                ;If last character, don't try and
        jz      abcl_have_nexts_a_space           ;  load next char's "a" space
        mov     ax,[si]
        add     ax,ax                             ;*2
        mov     dx,ax
        add     ax,ax                             ;*4
        add     ax,ax                             ;*8
        add     ax,dx                             ;*10
        .errnz  size ABC_FONT_ENTRIES - 10
        xchg    ax,bx
        mov     dx,fsCharOffset[bx].abc_a_space   ;dx = Next characters a_space
        xchg    ax,bx

        public  abcl_have_nexts_a_space
abcl_have_nexts_a_space:
        mov     ax,fsCharOffset[bx].abc_b_space
        add     dx,fsCharOffset[bx].abc_c_space   ;dx = c_space plus next a_space
        add     dx,char_extra
        push    bx                                ;Must save char index
        test    accel,HAVE_WIDTH_VECT
        jz      abcl_have_width
        les     bx,lp_dx
        assumes es,nothing
        mov     dx,word ptr es:[bx]               ;Next starting pos is the DX increment
        inc     bx
        inc     bx
        mov     lp_dx.off,bx
        mov     es,selFont
        assumes es,FontSeg
        sub     dx,ax                             ;Remove character's width

;/*
;**     DX contains any adjustment to the next characters starting
;**     position.  If this number is negative, then we'll be stepping
;**     over the previous character.
;**
;**     We don't allow a character to start before the previous
;**     character.  We'll have to enforce this at this point by
;**     making sure that any negative adjustment is less than or
;**     equal to the character width.
;*/

abcl_have_width:
        or      dx,dx
        jge     abcl_adjustment_ok
        add     dx,ax                             ;Don't allow the backwards step
        sbb     bx,bx                             ;  to go beyond the start of this
        and     dx,bx                             ;  character
        sub     dx,ax

abcl_adjustment_ok:
        pop     bx                                ;Restore char index

abcl_very_first_enters_here:
        add     ax,di                             ;AX = rhs of character
        cmp     clip.rcs_pts1.pts_x,ax
        jl      abcl_current_is_visible           ;Some part of char is visible


;/*
;**        If the adjustment for the character width is greater than the
;**        actual width of the character, then it is possible that the
;**        dummy pixels could become visible.  If the adjustment for the
;**        character width is less than the actual character width, then
;**        the dummy pixel (negative dummy pixels?) cannot become visible.
;/*

        add     ax,dx                             ;Next char starts at AX
        mov     di,clip.rcs_pts1.pts_x
        cmp     di,ax
        jl      abcl_dummy_is_visible             ;Some part of dummy char became visible
        xchg    di,ax                             ;Set start of next character

abcl_see_if_next:
        or      cx,cx
        jnz     abcl_next_char                    ;See if next character
        jmp     build_ret_addr                    ;Return to caller



;/*
;**       The dummy character is the first character which became
;**       visible.  Just set the starting X to clip.rcs_pts1.pts_x, and shorten
;**       the width of the dummy character appropriately.
;*/

abcl_dummy_is_visible:
        xchg    ax,dx                             ;Set DX = # pixels in dummy
        sub     dx,di
        xor     ax,ax                             ;Show no real character
        jmp     short abcl_all_done


;/*
;**     So here we are, we have a character which will become visible,
;**     and possibly have some adjustment to the character.
;**
;**     Our registers currently contain:
;**
;**             AX = rhs of character
;**             BX = index into offset/width table
;**             CX = # of characters left in the string
;**             DX = # of extra pixels (zero or positive)
;**             DI = starting X offset
;**             ES = FontSeg
;**             DS:SI --> string
;*/


abcl_current_is_visible:
        sub     ax,di                             ;Restore width of the character
        mov     bx,fsCharOffset[bx].fe_dBits.lo
        add     bx,amt_clipped_on_top             ;Adjust pointer for any clipping


;/*
;**       Instead of incrementing the current position by 8 and
;**       having to recover the real current position, we just
;**       slide the clip region left.  It has the same effect.
;*/

        push    dx                                ;Save extra pixels to be added
        mov     dx,clip.rcs_pts1.pts_x
        sub     dx,di                             ;Compute bits until we're visible
        je      abcl_save_first                   ;Starts on clip edge
        sub     dx,8                              ;Is current byte visible?
        jl      abcl_have_vis_start               ;  Yes

abcl_step_clipped_char:
        sub     ax,8                              ;Shorten the width of the character
        add     di,8                              ;Move current position right
        add     bx,lfd.font_height                ;Move to next column of character
        sub     dx,8                              ;Is current byte visible?
        jge     abcl_step_clipped_char            ;  No


;/*
;**        If the lhs of the clip region and the starting X of the
;**        character are in different bytes, then the FIRST_IN_PREV
;**        flag must be set.  Only a clipped character can set this
;**        flag.
;*/

abcl_have_vis_start:
        mov     dx,clip.rcs_pts1.pts_x
        xor     dx,di
        and     dx,not 7
        jz      abcl_save_first                  ;In same byte
        or      excel,FIRST_IN_PREV


;/*
;**       We have the start of the first character which is visible.
;**       We let the routine we're about to call push the character
;**       since it will handle both right clipping (if needed) and
;**       fat characters.
;/*

abcl_save_first:
        pop     dx                                ;Restore extra pixels

abcl_all_done:
        jmp     short abc_clip_enters_here

;/*
;**       abc - worse case, with rhs clipping
;**
;**       Currently:
;**               DS:SI --> current character in the string
;**               ES:    =  font segment
;**               DI     =  current X position
;**               CX     =  number of bytes left in the string
;*/

        public  abc_next_char
abc_next_char:
        xor     dx,dx                             ;Zero extra pels so far
        lodsw                                     ;Get this char's offset
        add     ax,ax                             ;*2
        mov     bx,ax
        add     ax,ax                             ;*4
        add     ax,ax                             ;*8
        add     bx,ax                             ;*10
        .errnz  size ABC_FONT_ENTRIES - 10
        dec     cx                                ;If last character, don't try and
        jz      abc_have_nexts_a_space            ;  load next char's "a" space
        mov     ax,[si]
        add     ax,ax                             ;*2
        mov     dx,ax
        add     ax,ax                             ;*4
        add     ax,ax                             ;*8
        add     ax,dx                             ;*10
        .errnz  size ABC_FONT_ENTRIES - 10
        xchg    ax,bx
        mov     dx,fsCharOffset[bx].abc_a_space
        xchg    ax,bx

        public  abc_have_nexts_a_space
abc_have_nexts_a_space:
        mov     ax,fsCharOffset[bx].abc_b_space
        add     dx,fsCharOffset[bx].abc_c_space
        add     dx,char_extra
        mov     bx,fsCharOffset[bx].abc_fe_dBits.lo
        add     bx,amt_clipped_on_top            ;Adjust pointer for any clipping
        push    bx
        test    accel,HAVE_WIDTH_VECT
        jz      abc_have_width
        les     bx,lp_dx
        assumes es,nothing
        mov     dx,word ptr es:[bx]
        inc     bx
        inc     bx
        mov     lp_dx.off,bx
        mov     es,selFont
        assumes es,FontSeg
        sub     dx,ax                             ;Remove character's width
                                                  ;DX is user's incr-b_space

;/*
;**     AX is b_space of current character
;**
;**     DX contains any adjustment to the next characters starting
;**     position.  If this number is negative, then we'll be stepping
;**     over the previous character.
;**
;**     We don't allow a character to start before the previous
;**     character.  We'll have to enforce this at this point by
;**     making sure that any negative adjustment is less than or
;**     equal to the character width.
;*/

        public  abc_have_width
abc_have_width:
        or      dx,dx
        jge     abc_adj_is_ok
        add     dx,ax                             ;Don't allow the backwards step
        sbb     bx,bx                             ;  to go beyond the start of this
        and     dx,bx                             ;  character
        sub     dx,ax

abc_adj_is_ok:
        pop     bx                                ;Restore bits offset

        public  abc_clip_enters_here
abc_clip_enters_here:
        or      ax,ax                             ;If character width is 0,
        jz      abc_check_dummy                   ;  might still have dummy char
        or      dx,dx                             ;Any adjustment to the width?
        jle     abc_have_adj_width                ;No extra pixels to add
        push    bx                                ;Add as many extra pixels as possible
        mov     bx,ax                             ;  into the empty space of this
        neg     ax                                ;  character
        and     ax,7                              ;AX = # extra pixels which will fit
        jz      abc_have_entire_width             ;None will fit
        cmp     ax,dx
        jl      abc_have_what_fits                ;Some extra pixels will not fit
        mov     ax,dx                             ;All pixels will fit, make DX = 0

abc_have_what_fits:
        sub     dx,ax                             ;DX = extra for the dummy character

abc_have_entire_width:
        add     ax,bx                             ;Set number of pixels to use in char
        pop     bx

        public  abc_have_adj_width
abc_have_adj_width:
        mov     num_null_pixels,dx                ;Save number of dummy pixels
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     abc_char_is_clipped               ;Clipped (or first pixel of next is)

abc_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If character is less than 8 bits
        jbe     abc_width_ok                      ;  wide, push it's data

abc_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        add     bx,lfd.font_height                ;  of the remaining width
        cmp     ax,8
        ja      abc_still_wide

abc_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits
        mov     dx,num_null_pixels

abc_check_dummy:
        xchg    ax,dx                             ;Just incase we go backwards
        or      ax,ax
        jz      abc_see_if_next                   ;No pixels for justification
        jl      abc_going_back
        mov     bx,null_char_offset
        mov     dx,di                             ;Compute phase
        and     dl,7
        add     di,ax                             ;DI = next char's X position
        cmp     di,clip.rcs_pts2.pts_x
        jge     abc_dummy_is_clipped              ;Clipped (or first pixel of next is)

abc_dummys_been_clipped:
        mov     dh,dl                             ;Need phase in DH
        mov     dl,8                              ;Need 8 for size in DL if fat
        cmp     ax,8                              ;If dummy is less than 8 bits
        jbe     abc_dummy_width_ok                ;  wide, push it's data

abc_dummy_still_wide:
        push    dx                                ;Push data showing phase,
        push    bx                                ;  character is 8 wide, then
        sub     ax,8                              ;  create another character
        cmp     ax,8
        ja      abc_dummy_still_wide

abc_dummy_width_ok:
        mov     ah,dh
        push    ax                                ;Save width and phase
        push    bx                                ;Save offset to bits

abc_see_if_next:
        cmp     sp,min_stack                      ;Stack compare must be unsigned
        jb      abc_restart                       ;Not enough stack for another character
        or      cx,cx
        jle     abc_all_done
        jmp     abc_next_char                     ;Until all characters pushed

abc_all_done:
        mov     ax,di                             ;Next character starts here
        jmp     build_ret_addr


;/*
;**     The dummy is either clipped, or it's last pixel is
;**     the last pixel which will fit within the clipping rhs.
;**     Adjust it's width so it fits, set the remaining character
;**     count to 0 so the loop will terminate, and reenter the
;**     code where we came from.
;**
;**     If the width adjustment was negative, we would never have
;**     reached this code, so ignore any restart.
;*/

abc_dummy_is_clipped:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        xor     cx,cx                             ;Show this as last character
        jmp     abc_dummys_been_clipped           ;Finish here

;/*
;**     This character is either clipped, or it's last pixel is
;**     the last pixel which will fit within the clipping rhs.
;**
;**     If there is a  negative adjustment to the width of the
;**     character, it is possible that the next character could
;**     be partially visible.  We'll have set up for a restart
;**     if this is the case.
;**
;**     If this is the last character of the string, then there
;**     is no problem
;**
;**     If no negative adjustment, adjust it's width so it fits,
;**     set the remaining character count to 0 so the loop will
;**     terminate, and reenter the code where we came from.
;*/

abc_char_is_clipped:

        push    dx                                ;If num_null_pixels < 0, then
        mov     dx,num_null_pixels                ;  a restart might be possible
        or      dx,dx
        jl      abc_might_need_restart            ;Might need a restart

abc_clipped_no_restart:
        mov     cx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,cx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,cx                             ;Set new rhs
        xor     cx,cx                             ;Don't want any extra pixels
        mov     num_null_pixels,cx
        pop     dx                                ;CX 0 to show no more chars
        jmp     abc_been_clipped                  ;Finish here


;/*
;**       Might be looking a restart in the face.  Compute where the
;**       next character would start, and if it is to the left of
;**       clip.rcs_pts2.pts_x, then a restart is needed.
;*/

abc_might_need_restart:
        or      cx,cx                             ;If last character
        jz      abc_clipped_no_restart            ;  then no restart needed
        add     dx,di                             ;Compute next starting x
        sub     dx,clip.rcs_pts2.pts_x
        jge     abc_clipped_no_restart            ;Rest of string is clipped

;/*
;**       Will have to force a restart for the next character.  We
;**       can do this by computing the number of pixels between where
;**       where the next character starts and clip.rcs_pts2.pts_x.  This
;**       negative number will be stuffed into num_null_pixels, so when
;**       we reenter the main loop, we'll force a restart after pushing
;**       the character data,
;*/

        mov     num_null_pixels,dx
        mov     dx,clip.rcs_pts2.pts_x            ;Compute number of pixels
        sub     di,dx                             ;  which have to be clipped
        sub     ax,di                             ;Set new character width
        mov     di,dx                             ;Set new rhs
        pop     dx
        jmp     abc_been_clipped                  ;Finish here


;/*
;**        I have the unfortunate task of informing you that the next
;**        character will start somewhere in the middle of the current
;**        character.  If this is the last character of the string,
;**        then nothing need be done.  If this isn't the last character,
;**        then a restart will be needed.
;/*

abc_going_back:
        add     ax,di                             ;Set position of next character
        jmp     build_ret_addr



;/*
;**       Out of stack space.  Set up for a restart.
;*/

abc_restart:
        mov     ax,di
        jmp     build_ret_addr

abc_case        endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  pad_left_hand_side  
;*
;* DESCRIPTION   = This routine is called when the text string isn't clipped on the 
;*                 left side.  It attempts to pad the character with 0's if at all  
;*                 possible.                                                        
;*                                                                                  
;*                 If we can pad to the left of the first character with 0's, then  
;*                 we can use the full byte code, which is many times faster than   
;*                 the partial byte code.                                           
;*                                                                                  
;*                 If we do pad, we must update both current_lhs and the starting   
;*                 X coordinate which will be used by the main loop code.           
;*
;*                 Registers Preserved:       
;*                       CX,SI,DI,DS,ES,FLAGS 
;*                 Registers Destroyed:       
;*                       AX,BX,DX             
;*
;* INPUT         = DS:SI --> current character in the string               
;*                 ES:    =  font segment                                  
;*                 CX     =  number of characters in the string            
;*                 DI     =  current X position (and therefore starting x) 
;*
;* OUTPUT        = DS:SI --> current character in the string   
;*                 ES:    =  font segment                      
;*                 CX     =  number of characters in the string
;*                 DI     =  current X position                
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

pad_left_hand_side      proc near

        mov     ax,di                             ;Get starting x coordinate
        and     ax,7                              ;Address MOD 8 is amount to pad
        jz      plhs_all_done                     ;At byte boundary, don't need padding


;/*
;**       If we're in transparent mode, we can always create a dummy
;**       character of 0's for the left side to avoid any left clipping
;*/

        test    accel,IS_OPAQUE                  ;If in transparent mode, we can
        jz      plhs_add_padding                 ;  always add the padding


;/*
;**       In opaque mode.  If there is an opaquing rectangle, try and pad
;**       the left side up to the byte boundary. If we cannot make it to
;**       the byte boundary, go as far as we can so that the opaquing code
;**       can skip the byte.
;**
;**
;**       If there isn't an opaque rectangle, we cannot do any padding.
;*/

        mov     bl,excel
        not     bl
        test    bl,OPAQUE_RECT+BOUNDED_IN_Y
        jnz     plhs_all_done                     ;Cannot add any padding
        mov     bx,di
        sub     bx,o_rect.rcs_pts1.pts_x
        jle     plhs_all_done                     ;Cannot add any.  Darn
        smin_ax bx                                ;Set AX = number of bits to pad


;/*
;**       Some number of 0's can be added to the left of the character.
;**       Add them, then move the lhs left by that amount.
;*/

plhs_add_padding:
        mov     dx,di                             ;DI = start x = text_bbox.rcs_pts1.pts_x
        sub     dx,ax                             ;Set new lhs of text bounding box
        mov     current_lhs,dx
        mov     ah,dl                             ;Set phase (x coordinate) of char
        and     ah,7
        pop     dx
        push    ax                                ;Width and phase of null character
        push    null_char_offset                  ;Offset in font of null character
        jmp     dx

plhs_all_done:
        ret

pad_left_hand_side endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  pad_right_hand_side 
;*
;* DESCRIPTION   = This routine is called once the text string has been pushed onto    
;*                 the stack.  It pads the character on the right up to a byte
;*                 boundary if possible.
;*                                                                                     
;*                 We always pad out to a byte boundary with 0 since it makes the      
;*                 stopping condition in the driving loop simpler since it never       
;*                 has to check to see if it has any more bytes of data left, it       
;*                 knows it does.  It just checks after each destination column        
;*                 has been output to see if anything else exists.                     
;*                                                                                     
;*                 The clipping mask will be computed to the last pixel we can         
;*                 alter.  In transparent mode, this will always be to the byte        
;*                 boundary.  In opaque mode, it depends on the opaquing rectangle.    
;*
;*                 Registers Preserved:                 
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS  
;*                 Registers Destroyed:                 
;*                       AX,BX,DX                       
;*
;*
;* INPUT         = DS:SI --> current character in the string            
;*                 ES:    =  font segment                               
;*                 DI     =  X position where next char would have gone 
;*
;* OUTPUT        = DS:SI --> current character in the string                   
;*                 ES:    =  font segment                                      
;*                 DI     =  rhs of the string, padded to boundary if possible 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C' set if no interval to output 
;*
;**************************************************************************/


        assumes ds,nothing
        assumes es,FontSeg
        assumes ss,ss_variables

pad_right_hand_side     proc near

        mov     ax,di                             ;If next char would start at bit 0,
        and     al,7                              ;  then no padding is required.
        jz      prhs_have_rhs                     ;No padding needed
        mov     ah,al                             ;Save phase
        neg     al                                ;Set width needed
        and     al,7
        pop     bx
        push    ax                                ;Width and phase of null character
        push    null_char_offset                  ;Offset in font of null character
        push    bx
        xor     ah,ah                             ;Only want width of the nulls in AX
        test    accel,IS_OPAQUE                   ;If in transparent mode
        jz      prhs_new_rhs                      ;  move text_bbox to byte boundary
        mov     bl,excel
        not     bl
        test    bl,OPAQUE_RECT+BOUNDED_IN_Y
        jnz     prhs_have_rhs                     ;Cannot alter actual rhs
        mov     bx,o_rect.rcs_pts2.pts_x          ;Compute distance from where I am to
        sub     bx,di                             ;  where opaque rectangle ends
        jle     prhs_have_rhs                     ;Opaque rect is left of text end
        smin_ax bx                                ;Compute amount to move rhs

prhs_new_rhs:
        add     di,ax                             ;Slide rhs right

prhs_have_rhs:
        ret

pad_right_hand_side     endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  process_stack_data  
;*
;* DESCRIPTION   = The non-overlapped data which has been accumulated on the stack
;*                 is output using the supplied dispatch tables.
;*
;*                 Registers Destroyed:   
;*                       AX,BX,CX,DX,SI,DI
;*                 Registers Preserved:   
;*                       DS,ES,BP         
;*
;* INPUT         = GRAF_ENAB_SR set for all planes enabled          
;*                 Tonys_bar_n_grill initialized to background color
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        assumes ds,nothing
        assumes es,nothing
        assumes ss,ss_variables

process_stack_data proc near


;/*
;**       The EGA needs a little special handling at this point.
;**
;**       The full opaque byte code expects the EGA to be correctly
;**       programmed for it's needs.  The EGA opaque partial byte
;**       code will correctly restore the adapter to the needed mode
;**       if it is called and RES_EGA_INNER is set.
;**
;**       So, if there is no first byte and we're in opaque mode,
;**       we must program the ega correctly for the inner loop.
;**       If there is a first byte and an inner loop, then we want
;**       to set the RES_EGA_INNER flag.
;**
;**       If in transparent mode, we must set the set/reset register
;**       to the foreground (text) color.
;*/


psd_pre_proc:
        les     di,lp_surface                     ;--> destination surface
        assumes es,nothing                        ;  (need EGAMem if this is the device)

        mov     bl,excel
        test    bl,IS_DEVICE                      ;Only preprocess if this is
        jz      psd_pp_done                       ;  the EGA
        test    accel,IS_OPAQUE
        jz      psd_pp_ega_trans
        mov     cx,inner_byte_count
        jcxz    psd_pp_done                       ;No inner loop, don't set the bit
        or      bl,RES_EGA_INNER                  ;Assume first byte
        cmp     left_clip_mask,0
        jne     psd_pp_have_first                 ;First byte
        call    set_ega_opaque_mode               ;No first, must set for inner loop
        jmp     short psd_pp_done

psd_pp_have_first:
        mov     excel,bl                          ;Show reset needed
        jmp     short psd_pp_done

psd_pp_ega_trans:
        mov     dx,EGA_BASE + GRAF_ADDR
        mov     ah,byte ptr colors[FOREGROUND]
        mov     al,GRAF_SET_RESET
        out16   dx,ax

psd_pp_ega_xor:
        mov     al,accel
        mov     ah,DR_XOR
        shr     al,2
        jc      psd_pp_ega_have_mode
        .errnz  IS_XOR_TEXT-00000010b
        mov     ah,DR_OR
        shr     al,1
        jc      psd_pp_ega_have_mode
        .errnz  IS_OR_TEXT-00000100b
        mov     ah,DR_SET
psd_pp_ega_have_mode:
        mov     al,GRAF_DATA_ROT
        out16   dx,ax

psd_pp_ega_no_xor:      
        mov     ax,MM_ALL shl 8 + GRAF_ENAB_SR
        out16   dx,ax
        mov     al,GRAF_BIT_MASK                  ;Transparent mode expects GRAF_ADDR
        out     dx,al                             ;  to be set to the bitmask register

psd_pp_done:
        mov     ds,selFont
        assumes ds,nothing

        mov     ax,text_bbox.rcs_pts1.pts_y       ;Compute Y component of the string
        mul     next_scan
        add     di,ax
        add     di,scan_start                     ;Add delta into scan



;/*
;**       It is possible that the first character requires clipping.
;**       If the clip mask is non-zero, then this is the case.
;*/


        mov     bx,non_clipped_table              ;Table if not clipped
        mov     dl,0FFh                           ;initialize OR-mask for clipped bits
        mov     al,left_clip_mask
        or      al,al
        jz      psd_not_clipped                   ;No partial first byte
        inc     inner_byte_count                  ;One extra time through the loop
        mov     bx,clipped_table
        inc     dl                                ;set OR-mask to 00h

psd_not_clipped:
        or      al,dl                             ;if no clipping, set AL to 0FFh
        mov     ss_clip_mask,al
        mov     al,16                             ;Looking to cross two byte boundaries
        test    excel,FIRST_IN_PREV               ;Does first char span a boundary?
        jnz     psd_collect_chars                 ;Need to cross two
        mov     al,8                              ;Only 1 byte boundary (BL = 8)


;/*
;**       This is the start of the real loop where we zip through
;**       all the data we pushed onto the stack.
;*/


psd_collect_chars:
        xor     si,si                             ;Dispatch table index
        mov     dx,bp                             ;Save frame pointer
        mov     bp,buffer                         ;--> next character's data
        mov     cx,word ptr [bp].fd_width         ;CH = X position, CL = width
        errnz   fd_phase-fd_width-1

        add     ch,cl                             ;CH = next char's start bit position
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-1 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-2 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-3 * size frame_data]
        cmp     ch,al
        jb      psd_unlikely_cases
        ja      psd_have_more_than_enough

psd_have_exact_fit:
        mov     cx,si                             ;# of source character involved
        shl     si,1                              ;Compute index into dispatch table
        mov     bx,word ptr cs:[bx][si]           ;Get address of drawing function
        shl     si,1
        errnz   <(size frame_data) - 4>
        neg     si                                ;Going backwards
        lea     ax,[bp].[-(size frame_data)][si]
        xchg    bp,dx                             ;Restore frame pointer
        mov     buffer,ax                         ;Save new buffer pointer

;/*
;**     Call the procedure with the following register variables
;**
;**         DS:     =  Font bits segment
;**         ES:DI  --> destination
;**         DX      =  pointer to frame data
;**         CX      =  # of source characters - 1
;**         AX      =  Visible height
;*/

        mov     ax,clipped_font_height
        call    bx                                ;Invoke drawing routine
        mov     al,8                              ;First doesn't cross byte boundary
        mov     bx,non_clipped_table              ;No clipping required
        mov     ss_clip_mask,0FFh
        dec     inner_byte_count
        jg      psd_collect_chars
        jmp     short psd_see_about_last

psd_have_more_than_enough:
        mov     cx,si                             ;# of source character involved
        shl     si,1                              ;Compute index into dispatch table
        mov     bx,word ptr cs:[bx][si]           ;Get address of drawing function
        shl     si,1
        errnz   <(size frame_data) - 4>
        neg     si                                ;Going backwards
        lea     ax,[bp][si]
        xchg    bp,dx                             ;Restore frame pointer
        mov     buffer,ax                         ;Save new buffer pointer

;/*
;**     Call the procedure with the following register variables
;**
;**         DS:     =  Font bits segment
;**         ES:DI  --> destination
;**         DX      =  pointer to frame data
;**         CX      =  # of source characters - 1
;**         AX      =  Visible height
 */

        mov     ax,clipped_font_height
        call    bx                                ;Invoke drawing routine
        mov     al,16                             ;First crosses byte boundary
        mov     bx,non_clipped_table              ;No clipping required
        mov     ss_clip_mask,0FFh
        dec     inner_byte_count
        jle     short psd_see_about_last
        jmp     psd_collect_chars


psd_unlikely_cases:
        inc     si
        add     ch,[bp].fd_width[-4 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-5 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-6 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        inc     si
        add     ch,[bp].fd_width[-7 * size frame_data]
        cmp     ch,al
        ja      psd_have_more_than_enough
        jmp     psd_have_exact_fit               


psd_see_about_last:
        and     excel,not RES_EGA_INNER          ;Don't restore ega after partial byte
        xor     cx,cx                            ;Zero last byte clipped mask
        xchg    cl,right_clip_mask               ;  and get it
        jcxz    psd_exit                         ;No last byte to deal with
        mov     ss_clip_mask,cl                  ;have last byte, set clip mask
        mov     bx,clipped_table                 ;Must use the clipped table
        jmp     psd_collect_chars

psd_exit:
        ret

process_stack_data endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  set_ega_opaque_mode   
;*
;* DESCRIPTION   = The ega is programmed for entire byte opaquing           
;*
;*                 Registers Destroyed:    
;*                       AX, DX            
;*                 Registers Preserved:    
;*                       BX,CX,SI,DI,DS,ES 
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,EGAMem

        public  set_ega_opaque_mode
set_ega_opaque_mode     proc near

        mov     dx,EGA_BASE + SEQ_DATA
        mov     al,MM_ALL
        out     dx,al
        mov     ax,colors
        mov     dl,accel
        test    dl,IS_XOR_TEXT or IS_OR_TEXT
        jz      seom_overwrite_text
        test    dl,IS_XOR_TEXT
        mov     dl,GRAF_ADDR
        jnz     seom_xor_text

;/*
;** ORed mode text doesn't use the EGA in XOR mode.  Instead we just use
;** the set/reset register for any plane where the foreground color is
;** the same as the background color, or the background color is a one,
;** and use the character pattern where the foreground color is a 1 and
;** the background is 0:
;**
;**       fgcolor  bkcolor |  result
;**       -------  ------- |  ------               This assumes that the character
;**          0        0    | bkcolor               pattern is a 1 where the fore-
;**          0        1    | bkcolor               ground color is to be used and
;**          1        0    | character             a 0 where the background color
;**          1        1    | bkcolor               is to be used.
;*/

        mov     al,GRAF_SET_RESET
        out16   dx,ax
        .errnz  BACKGROUND-1                      ;Must be in AH
        mov     al,byte ptr colors[FOREGROUND]
        not     ah
        and     ah,al                             ;1 wherever FG = 1 and BK = 0
        not     ah                                ;1 wherever set/reset to be used
        mov     al,GRAF_ENAB_SR
        out16   dx,ax
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        jmp     short seom_finish_up

;/*
;** For XORed opaque text, use the EGA in XOR mode. !!!expand on this
;**
;**       fgcolor  bkcolor |  result
;**       -------  ------- |  ------               This assumes that the character
;**          0        0    | bkcolor               pattern is a 1 where the fore-
;**          0        1    | bkcolor               ground color is to be used and
;**          1        0    | character             a 0 where the background color
;**          1        1    | ~character            is to be used.
;**
;** The set/reset is loaded with 0's so that the xor has no effect.
;** The planes where the foreground color is zero will be enabled for
;** set/reset.  Other planes will take the host data and xor it into
;** the background color stored in the latches.
;*/

seom_xor_text:
        mov     ax,GRAF_SET_RESET                ;Want 0's for color
        out16   dx,ax
        mov     ah,byte ptr colors[FOREGROUND]
        jmp     short seom_xor_text_finish

seom_overwrite_text:
        xor     ah,al
        mov     al,GRAF_SET_RESET
        mov     dl,GRAF_ADDR
        out16   dx,ax
seom_xor_text_finish:
        not     ah
        mov     al,GRAF_ENAB_SR
        out16   dx,ax
        mov     ax,DR_XOR shl 8 + GRAF_DATA_ROT
seom_finish_up:
        out16   dx,ax
        mov     ax,0FFh shl 8 + GRAF_BIT_MASK
        out16   dx,ax
        mov     al,tonys_bar_n_grill              ;Inintialize EGA latches (not used
        ret                                       ;  for OR mode text)

set_ega_opaque_mode     endp

        page
;/***************************************************************************
;*
;* PUBLIC ROUTINE  prepare_for_overlap 
;*
;* DESCRIPTION   = We will step backwards somewhere within the string.  Opaque the                  
;*                 area where the string will go and set transparent mode for the 
;*                 actual text output routine.                                                      
;*                                                                                                  
;*                 Registers Destroyed:           
;*                       AX,BX,CX,DX,SI,DI,DS,ES  
;*                 Registers Preserved:           
;*                       None                     
;*
;* INPUT         = bl = accel    
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = to build_all_done if nothing will show 
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing
        assumes ss,ss_variables

        public prepare_for_overlap
prepare_for_overlap proc near

        mov     ax,clip.rcs_pts2.pts_x
        mov     cx,x                              ;x is screen lhs
        mov     bx,rhs                            ;Zero based rhs
        add     bx,cx                             ;BX = screen rhs
        jo      pfo_have_rhs                      ;Use clip.rcs_pts2.pts_x for right side
        smin_ax bx

pfo_have_rhs:
        xchg    ax,bx                             ;Need rhs in BX
        mov     ax,clip.rcs_pts1.pts_x
        smax_ax cx
        cmp     bx,ax
        jle     pfo_exit_nothing_shows            ;Null or negative interval


;/*
;**       The interval will show.  Dummy this up as a call to the
;**       opaque rectangle code to output the bounding box.  Since
;**       TEXT_VISIBLE was cleared by build_string, the opaque code
;**       will not perform an intersection of text_bbox and o_rect.
;/*

        mov     wc_opaque_lhs,ax                 ; Save lhs/rhs incase we have an
        mov     wc_opaque_rhs,bx                 ;   opaquing rectangle
        or      wc_flags,WC_SET_LR               ; Set left/right into text bbox
        push    o_rect.rcs_pts1.pts_x            ; Save real o_rect bbox
        push    o_rect.rcs_pts2.pts_x
        push    o_rect.rcs_pts1.pts_y
        push    o_rect.rcs_pts2.pts_y
        mov     cx,text_bbox.rcs_pts1.pts_y
        mov     dx,text_bbox.rcs_pts2.pts_y
        mov     o_rect.rcs_pts1.pts_x,ax         ; Set text bbox as area to opaque
        mov     o_rect.rcs_pts2.pts_x,bx
        mov     o_rect.rcs_pts1.pts_y,cx
        mov     o_rect.rcs_pts2.pts_y,dx
        mov     bl,excel
        call    output_o_rect
        pop     o_rect.rcs_pts2.pts_y
        pop     o_rect.rcs_pts1.pts_y
        pop     o_rect.rcs_pts2.pts_x
        pop     o_rect.rcs_pts1.pts_x

        and     accel,not IS_OPAQUE              ; Will output text in transparent mode

pfo_exit:
        ret

pfo_exit_nothing_shows:
        pop     ax
        jmp     build_restore_opaque

prepare_for_overlap endp

sEnd    Code
        end
