;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = 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
;*
;*
;* 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
;*   09/04/92              53341  Richard Wooley Calculate the stack limit
;*   ??/??/92              53536  Paul King CMVC_53536
;*   ??/??/92              52931  Paul King CMVC_52931
;*   06/03/93              69423  Remove special case for all ones because
;*                                we might be doing an XOR.
;*   10/28/93              75099  We really shouldn't switch banks when
;*                                writing to a bitmap.
;*
;*****************************************************************************/

        .386

        .xlist

INCL_GRE_CLIP           equ     1
INCL_FONTFILEFORMAT     equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1

        include pmgre.inc
        include fontmap.inc
        include driver.inc
        include egafam.inc
        include strblt.inc
        include pointer.inc
        include extern.inc
        include protos.inc
Update_Bank     PROTO SYSCALL

        .list

        .MODEL FLAT

        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT

        .DATA
EXTERNDEF       Origin_bank:BYTE

ifdef  JTUNE        ;IBMJ
ALIGN 4
Upper4PPTable DWORD 64 DUP (0)
Lower4PPTable DWORD 16 DUP (0)
ClipAndMask DWORD 0
LastFgBg WORD 0
endif ;JTUNE        ;IBMJ

        .CODE

        EXTERN preset_pro_text          :NEAR
        EXTERN worst_case_ext           :NEAR
        EXTERN comp_byte_interval       :NEAR

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

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

build_string PROC SYSCALL, lp_DDC        :DWORD, lp_DestDev    :DWORD,
                           x             :DWORD, y             :DWORD,
                           lp_clip_rect  :DWORD, lp_string     :DWORD,
                           count         :DWORD, npAttrs       :DWORD,
                           lp_dx         :DWORD, lp_opaque_rect:DWORD,
                           eto_options   :DWORD
        LOCAL   accel           :BYTE
        LOCAL   excel           :BYTE
        LOCAL   wc_flags        :BYTE
        LOCAL   fbTranslate     :BYTE
        LOCAL   colors          :DWORD
        LOCAL   char_extra      :DWORD
        LOCAL   num_null_pixels :DWORD
        LOCAL   null_char_offset:DWORD
        LOCAL   lhs             :DWORD
        LOCAL   rhs             :DWORD
        LOCAL   concat          :DWORD
        LOCAL   pFont           :DWORD
        LOCAL   lfd             :local_font_def
        LOCAL   clip            :RECTL
        LOCAL   text_bbox       :RECTL
        LOCAL   o_rect          :RECTL
        LOCAL   smart_flags            :BYTE
        LOCAL   special_bm_opaque_color:BYTE
        LOCAL   num_planes             :BYTE
        LOCAL   left_clip_mask         :BYTE
        LOCAL   right_clip_mask        :BYTE
        LOCAL   cell_adjust            :DWORD
        LOCAL   buffer                 :DWORD
        LOCAL   fix_total_bytes        :DWORD
        LOCAL   next_scan              :DWORD
        LOCAL   next_plane             :DWORD
        LOCAL   next_scan_xor          :DWORD
        LOCAL   opaque_routine         :DWORD
        LOCAL   opaque_height          :DWORD
        LOCAL   lp_surface             :DWORD
        LOCAL   temp_off_lp_bits       :DWORD
        LOCAL   scan_start             :DWORD
        LOCAL   clipped_font_height    :DWORD
        LOCAL   amt_clipped_on_top     :DWORD
        LOCAL   clear_stack            :DWORD
        LOCAL   min_stack              :DWORD
        LOCAL   build_proc             :DWORD
        LOCAL   phase                  :DWORD
        LOCAL   x2                     :DWORD
        LOCAL   inner_loop             :DWORD
        LOCAL   clipped_table          :DWORD
        LOCAL   non_clipped_table      :DWORD
        LOCAL   inner_byte_count       :DWORD
        LOCAL   current_lhs            :DWORD
        LOCAL   current_rhs            :DWORD
        LOCAL   wc_opaque_lhs          :DWORD
        LOCAL   wc_opaque_rhs          :DWORD
        LOCAL   string_start_bias      :DWORD
        LOCAL   ret_addr               :DWORD
        LOCAL   unrolled_entry_point   :DWORD
        LOCAL   vect_one_in_first      :DWORD
        LOCAL   vect_two_in_first      :DWORD
        LOCAL   vect_one_in_middle     :DWORD
        LOCAL   vect_two_in_middle     :DWORD
        LOCAL   vect_one_in_last       :DWORD
        LOCAL   vect_two_in_last       :DWORD
        LOCAL   ret_addr_2             :DWORD
        LOCAL   ega_oc_saved_data      :DWORD
        LOCAL   current_banks                           :byte
        LOCAL   bitmap_type                             :byte
        LOCAL   colorphase                              :byte

;/*
;** Calculate the stack limit by replacing the low word of the
;** stack pointer by our STACK_SLOP value.  As we push data onto
;** the stack, we will check ESP against this value to prevent
;** stack overflow.  NOTE:  We assume that the stack ends at the
;** beginning of the current segment.
;**           
;*/

        mov     eax,esp                  ; Don't let stack trash our vars.
        mov     ax,STACK_SLOP
        mov     min_stack,eax

        mov     eax,text_bbox.rcl_xLeft ;Make text bbox a null interval
        mov     text_bbox.rcl_xRight,eax ;  We'll grow it as we progress
        mov     current_lhs,eax                   ;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     ecx,OFFSET non_justified_text
        test    bl,HAVE_WIDTH_VECT or ABC_FONT or HAVE_CHAR_EXTRA
        jz      build_have_proc
        mov     ecx,OFFSET 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     ecx,OFFSET worst_case
        test    bl,ABC_FONT
        jz      build_have_proc
        mov     ecx,OFFSET abc_case
        or      wc_flags,WC_FIRST                ;Very frist call is special

build_have_proc:

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

build_restart:
        mov     clear_stack,esp                   ;Used to clean the stack on exit
        mov     eax,esp                           ;Save buffer start pointer
        sub     eax,4
        mov     buffer,eax

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

        mov     esi,lp_string
        mov     al,excel
        mov     ah,accel
        mov     ecx,count
        mov     edi,x

        jmp     build_proc

        public  build_ret_addr
build_ret_addr::                                  ;build routines return here


        mov     count,ecx                         ;Save count
        mov     x,eax                             ;Save next char's start
        mov     lp_string,esi                    ;Save next character
        call    pad_right_hand_side              ;Fill to byte boundary if possible
        mov     current_rhs,edi                   ;Save rhs
        mov     ebx,edi                           ;Compute the interval data
        mov     edx,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,esi
        mov     scan_start,edi
        call    process_stack_data               ;Display the string
        mov     esp,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     eax,current_lhs
        mov     ebx,text_bbox.rcl_xLeft
        smin_ax ebx
        mov     text_bbox.rcl_xLeft,eax
        mov     eax,current_rhs
        mov     ebx,text_bbox.rcl_xRight
        smax_ax ebx
        mov     text_bbox.rcl_xRight,eax

build_no_o_rect:

        mov     ecx,count                         ;If no more characters
        jecxz   build_restore_opaque             ;  go home, have dinner, sleep


;/*
;**       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     edi,x
        mov     eax,edi                           ;Assume start will be current_lhs
        test    accel,IS_OPAQUE                  ;When opaque, must clip on
        jnz     build_clip_next_time             ;  a restart
        cmp     edi,clip.rcl_xLeft
        jge     build_no_clip_next_time

build_clip_next_time:

        or      bl,CLIPPED_LEFT                  ;Clipping is required
        mov     eax,clip.rcl_xLeft               ;  and clip.rcl_xLeft for clipping check
        smax_ax edi                              ;  (but only if start X > old clip
        mov     clip.rcl_xLeft,eax               ;   lhs)

build_no_clip_next_time:

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

build_all_done:

        mov     esp,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     ebx,wc_opaque_lhs                ;  and rhs incase we have an
        mov     text_bbox.rcl_xLeft,ebx       ;  opaque rectangle
        mov     ebx,wc_opaque_rhs
        mov     text_bbox.rcl_xRight,ebx

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

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


        public  non_justified_text

non_justified_text::

        mov     colorphase,0
        test    al,CLIPPED_LEFT
        jz      sc_no_left_clipping              ;No clipping needed on lhs
        mov     edx,clip.rcl_xLeft               ;Characters become visible here
        test    ah,FIXED_PITCH
        jz      spcl_next_char                    ;Proportional font
ifdef DBCS  ; DBCS device font support     ;IBMJ
 test    fsFont,NLSCA_FONT_DBCS_USED
 jnz     spcl_next_char     ;DBCS chars act as proportional font
endif;DBCS        ;IBMJ

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

        movzx   ebx,lfd.font_width               ;Fixed pitch font.

sfcl_next_char:

        add     edi,ebx                           ;Does this character become visible?
        cmp     edx,edi                   ;DX is clip.rcl_xLeft
        jl      sfcl_current_is_visible ;This char is visible
        add     esi,4
        loop    sfcl_next_char                    ;See if next character

sfcl_no_chars_visible:

        jmp     build_ret_addr                    ;Return to caller

sfcl_current_is_visible:

        sub     edi,ebx                           ;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:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        mov     eax,pFont

        ASSUME  eax:PTR FONTMAP, ebx:PTR FONT_ENTRIES

        movzx   eax,[eax].fsCharOffset[ebx].fe_width
        add     edi,eax                           ;0 width chars won't change x position
        cmp     edx,edi                   ;DX is clip.rcl_xLeft
        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     edi,eax                           ;Restore starting x of character
        push    eax
        mov     eax,pFont
        mov     ebx,[eax].fsCharOffset[ebx].fe_dBits
        pop     eax
        add     ebx,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     edx,edi                           ;Compute bits until we're visible
        je      spcl_save_first                  ;Starts on clip edge
        sub     edx,8                             ;Is current byte visible?
        jl      spcl_have_vis_start              ;  Yes

spcl_step_clipped_char:

        sub     eax,8                             ;Shorten the width of the character
        add     edi,8                             ;Move current position right
        add     bx,lfd.font_height               ;Move to next column of character
        sub     edx,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:
        add     edx,8
        mov     colorphase,dl
        mov     edx,clip.rcl_xLeft
        xor     edx,edi
        and     edx,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     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:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        push    edi
        mov     edi,pFont

        ASSUME  edi:PTR FONTMAP, ebx:PTR FONT_ENTRIES

        movzx   eax,[edi].fsCharOffset[ebx].fe_width
        mov     ebx,[edi].fsCharOffset[ebx].fe_dBits
        pop     edi
        or      eax,eax                           ;If width is 0, ignore character
        jz      scc_see_if_next
        add     ebx,amt_clipped_on_top           ;Adjust pointer for any clipping

scc_clip_enters_here:

        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        jge     scc_char_is_clipped              ;Clipped (or first pixel of next is)

scc_been_clipped:

        mov     dh,dl                             ;Need phase in DH
        cmp     eax,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    edx                               ;Push data showing phase,
        push    ebx                               ;  character is 8 wide, then
        sub     eax,8                             ;  create another character
        add     bx,lfd.font_height               ;  of the remaining width
        cmp     eax,8
        ja      scc_still_wide

scc_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits
        cmp     esp,min_stack                     ;Stack compare must be unsigned
        jb      scc_restart                       ;Not enough stack for another character

scc_see_if_next:

        dec     ecx
        jz      @f
        jmp     scc_next_char
@@:
        mov     eax,edi                           ;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     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        mov     ecx,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     ecx                               ;Adjust count for char just pushed
        mov     eax,edi                           ;Next character starts here
        jmp     build_ret_addr

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

        public  justified_text

justified_text::
        mov     colorphase,0
        test    excel,CLIPPED_LEFT
        jnz     jcl_next_char                     ;Clipping needed
        call    pad_left_hand_side               ;Might be able to pad lhs
        jmp     jc_next_char

jcl_next_char:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        mov     eax,pFont
        movzx   eax,[eax].fsCharOffset[ebx].fe_width
        mov     edx,char_extra

jcl_have_width:

        add     edi,eax                           ;DI = next chars starting X
        cmp     clip.rcl_xLeft,edi
        jl      jcl_current_is_visible           ;This char is visible
        add     edi,edx
        cmp     clip.rcl_xLeft,edi
        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.rcl_xLeft, and shorten
;**  the width of the dummy character appropriately.
;*/

jcl_dummy_is_visible:

        mov     edx,edi
        mov     edi,clip.rcl_xLeft            ;Starting X is clip.rcl_xLeft
        sub     edx,edi                           ;DX is # pixels in dummy
        xor     eax,eax                           ;Show no real character
        jmp     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     edi,eax                           ;Restore starting x of character
        push    eax
        mov     eax,pFont
        mov     ebx,[eax].fsCharOffset[ebx].fe_dBits
        pop     eax
        add     ebx,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    edx                               ;Save extra pixels
        mov     edx,clip.rcl_xLeft
        sub     edx,edi                           ;Compute bits until we're visible
        je      jcl_save_first                    ;Starts on clip edge
        sub     edx,8                             ;Is current byte visible?
        jl      jcl_have_vis_start               ;  Yes

jcl_step_clipped_char:

        sub     eax,8                             ;Shorten the width of the character
        add     edi,8                             ;Move current position right
        add     bx,lfd.font_height               ;Move to next column of character
        sub     edx,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:
        add     edx,8
        mov     colorphase,dl
        mov     edx,clip.rcl_xLeft
        xor     edx,edi
        and     edx,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     edx                               ;Restore extra pixels

jcl_all_done:

        jmp     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:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        mov     eax,pFont
        movzx   eax,[eax].fsCharOffset[ebx].fe_width
        mov     edx,char_extra

jc_have_width:

        or      eax,eax
        jz      jc_check_dummy                    ;If width is 0, might still have dummy
        push    eax
        mov     eax,pFont
        mov     ebx,[eax].fsCharOffset[ebx].fe_dBits
        pop     eax
        add     ebx,amt_clipped_on_top           ;Adjust pointer for any clipping

jc_clip_enters_here:

        mov     num_null_pixels,edx              ;Save # null pixels
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If character is less than 8 bits
        jbe     jc_width_ok                       ;  wide, push it's data

jc_still_wide:

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

jc_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits
        mov     edx,num_null_pixels

jc_check_dummy:

        or      edx,edx
        jz      jc_see_if_next                    ;No pixels for justification
        xchg    eax,edx                           ;Set ax = number of pixels to fill
        mov     ebx,null_char_offset
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If dummy is less than 8 bits
        jbe     jc_dummy_width_ok                ;  wide, push it's data

jc_dummy_still_wide:

        push    edx                               ;Push data showing phase,
        push    ebx                               ;  character is 8 wide, then
        sub     eax,8                             ;  create another character
        cmp     eax,8
        ja      jc_dummy_still_wide

jc_dummy_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits

jc_see_if_next:

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

jc_all_done:

        mov     eax,edi                           ;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     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        xor     ecx,ecx                           ;Dont't want any extra pixels
        mov     num_null_pixels,ecx
        inc     ecx                               ;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     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        mov     ecx,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     ecx                               ;Adjust count for char just pushed
        mov     eax,edi                           ;Next character starts here
        jmp     build_ret_addr

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


        public  worst_case

worst_case::
        mov     colorphase,0
        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:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        mov     eax,pFont
        movzx   eax,[eax].fsCharOffset[ebx].fe_width
        push    ebx                               ;Must save character index
        mov     ebx,lp_dx
        mov     edx,DWORD PTR [ebx]              ;DX is delta to next char's start
        add     ebx,4
        mov     lp_dx,ebx
        sub     edx,eax                           ;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      edx,edx
        jge     wccl_adjustment_ok
        add     edx,eax                           ;Don't allow the backwards step
        sbb     ebx,ebx                           ;  to go beyond the start of this
        and     edx,ebx                           ;  character
        sub     edx,eax

wccl_adjustment_ok:

        pop     ebx                               ;Restore char index
        add     eax,edi                           ;AX = rhs of character
        cmp     clip.rcl_xLeft,eax
        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     eax,edx                           ;Next char starts at AX
        mov     edi,clip.rcl_xLeft
        cmp     edi,eax
        jl      wccl_dummy_is_visible            ;Some part of dummy char became visible
        xchg    edi,eax                           ;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.rcl_xLeft, and shorten
;**       the width of the dummy character appropriately.
;*/

wccl_dummy_is_visible:

        xchg    eax,edx                           ;Set DX = # pixels in dummy
        sub     edx,edi
        xor     eax,eax                           ;Show no real character
        jmp     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     eax,edi                           ;Restore width of the character
        push    eax
        mov     eax,pFont
        mov     ebx,[eax].fsCharOffset[ebx].fe_dBits
        pop     eax
        add     ebx,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    edx                               ;Save extra pixels to be added
        mov     edx,clip.rcl_xLeft
        sub     edx,edi                           ;Compute bits until we're visible
        je      wccl_save_first                  ;Starts on clip edge
        sub     edx,8                             ;Is current byte visible?
        jl      wccl_have_vis_start              ;  Yes

wccl_step_clipped_char:

        sub     eax,8                             ;Shorten the width of the character
        add     edi,8                             ;Move current position right
        add     bx,lfd.font_height               ;Move to next column of character
        sub     edx,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:
        add     edx,8
        mov     colorphase,dl
        mov     edx,clip.rcl_xLeft
        xor     edx,edi
        and     edx,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     edx                               ;Restore extra pixels

wccl_all_done:

        jmp     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:

        lodsd
        add     eax,eax
        mov     ebx,eax
        add     eax,eax
        add     ebx,eax

        .errnz  (size FONT_ENTRIES) - 6

        mov     edx,pFont
        movzx   eax,[edx].fsCharOffset[ebx].fe_width
        mov     ebx,[edx].fsCharOffset[ebx].fe_dBits
        add     ebx,amt_clipped_on_top           ;Adjust pointer for any clipping
        push    ebx
        mov     ebx,lp_dx
        mov     edx,DWORD PTR [ebx]              ;DX is delta to next char's start
        add     ebx,4
        mov     lp_dx,ebx
        sub     edx,eax                           ;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      edx,edx
        jge     wcc_adj_is_ok
        add     edx,eax                           ;Don't allow the backwards step
        sbb     ebx,ebx                           ;  to go beyond the start of this
        and     edx,ebx                           ;  character
        sub     edx,eax

wcc_adj_is_ok:

        pop     ebx                               ;Restore bits offset

wcc_clip_enters_here:

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

wcc_have_what_fits:

        sub     edx,eax                           ;DX = extra for the dummy character

wcc_have_entire_width:

        add     eax,ebx                           ;Set number of pixels to use in char
        pop     ebx

wcc_have_adj_width:

        mov     num_null_pixels,edx              ;Save number of dummy pixels
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If character is less than 8 bits
        jbe     wcc_width_ok                      ;  wide, push it's data

wcc_still_wide:

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

wcc_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits
        mov     edx,num_null_pixels

wcc_check_dummy:

        xchg    eax,edx                           ;Just incase we go backwards
        or      eax,eax
        jz      wcc_see_if_next                  ;No pixels for justification
        jl      wcc_going_back
        mov     ebx,null_char_offset
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If dummy is less than 8 bits
        jbe     wcc_dummy_width_ok               ;  wide, push it's data

wcc_dummy_still_wide:

        push    edx                               ;Push data showing phase,
        push    ebx                               ;  character is 8 wide, then
        sub     eax,8                             ;  create another character
        cmp     eax,8
        ja      wcc_dummy_still_wide

wcc_dummy_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits

wcc_see_if_next:

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

wcc_all_done:

        mov     eax,edi                           ;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     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        mov     ecx,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    edx                               ;If num_null_pixels < 0, then
        mov     edx,num_null_pixels              ;  a restart might be possible
        or      edx,edx
        jl      wcc_might_need_restart           ;Might need a restart

wcc_clipped_no_restart:

        mov     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        xor     ecx,ecx                           ;Don't want any extra pixels
        mov     num_null_pixels,ecx
        inc     ecx                               ;Show this as last character
        pop     edx
        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.rcl_xRight, then a restart is needed.
;*/

wcc_might_need_restart:

        cmp     ecx,1                             ;If last character
        jle     wcc_clipped_no_restart           ;  then no restart needed
        add     edx,edi                           ;Compute next starting x
        sub     edx,clip.rcl_xRight
        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.rcl_xRight.  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,edx
        mov     edx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,edx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,edx                           ;Set new rhs
        pop     edx
        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     eax,edi                           ;Set position of next character
        dec     ecx                               ;Adjust count for char just pushed
        jmp     build_ret_addr



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

wcc_restart:

        mov     eax,edi
        dec     ecx                               ;Adjust count for char just pushed
        jmp     build_ret_addr


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


        public  abc_case

abc_case::

;/*
;** 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     ebx,DWORD PTR [esi]               ;Get "a" space for this
        imul    ebx,(size ABC_FONT_ENTRIES)
        mov     edx,pFont

        ASSUME  ebx:PTR ABC_FONT_ENTRIES

        ;movzx  edx,[edx].fsCharOffset[ebx].abc_a_space         ;@DMS
        movsx   edx,[edx].fsCharOffset[ebx].abc_a_space
        or      edx,edx
        jns     abc_special_dummy_needed;Positive, must deal with it

abc_not_first_time:

        xor     edx,edx                           ;No dummy needed

abc_special_dummy_needed:

        and     wc_flags,not WC_FIRST
        test    al,CLIPPED_LEFT
        mov     eax,0                             ;Preseve flags
        jnz     abcl_very_first_enters_here ;Clipping needed
        mov     num_null_pixels,edx              ;Cannot push!!
        call    pad_left_hand_side               ;Might be able to pad lhs
        mov     edx,num_null_pixels              ;Dummy >= zero
        xor     eax,eax                           ;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     edx,edx                           ;Zero extra pels so far
        lodsd                                     ;Get this char's offset
        add     eax,eax                           ;*2
        mov     ebx,eax
        add     eax,eax                           ;*4
        add     eax,eax                           ;*8
        add     ebx,eax                           ;*10

        .errnz  size ABC_FONT_ENTRIES - 10

        dec     ecx                               ;If last character, don't try and
        jz      abcl_have_nexts_a_space ;  load next char's "a" space
        mov     eax,DWORD PTR [esi]
        add     eax,eax                           ;*2
        mov     edx,eax
        add     eax,eax                           ;*4
        add     eax,eax                           ;*8
        add     eax,edx                           ;*10

        .errnz  size ABC_FONT_ENTRIES - 10

        xchg    eax,ebx
        mov     edx,pFont

        ASSUME  edx:PTR FONTMAP, ebx:PTR ABC_FONT_ENTRIES

        movzx   edx,[edx].fsCharOffset[ebx].abc_a_space ;dx = Next characters a_space
        xchg    eax,ebx

        public  abcl_have_nexts_a_space

abcl_have_nexts_a_space::

        push    esi
        mov     esi,pFont

        ASSUME  esi:PTR FONTMAP, ebx:PTR ABC_FONT_ENTRIES

        movzx   eax,[esi].fsCharOffset[ebx].abc_b_space
        add     dx,[esi].fsCharOffset[ebx].abc_c_space ;dx = c_space plus next a_space
        pop     esi
        add     edx,char_extra
        push    ebx                               ;Must save char index
        test    accel,HAVE_WIDTH_VECT
        jz      abcl_have_width
        mov     ebx,lp_dx
        ;movzx  edx,word ptr es:[ebx]            ;Next starting pos is the DX increment
        ;inc    ebx
        ;inc    ebx
        ; @DMS keeping up with 16color fixes
        mov     edx,DWORD PTR [ebx]              ;Next starting pos is the DX increment
        add     ebx,4

        mov     lp_dx,ebx
        sub     edx,eax                           ;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      edx,edx
        jge     abcl_adjustment_ok
        add     edx,eax                           ;Don't allow the backwards step
        sbb     ebx,ebx                           ;  to go beyond the start of this
        and     edx,ebx                           ;  character
        sub     edx,eax

abcl_adjustment_ok:

        pop     ebx                               ;Restore char index

abcl_very_first_enters_here:

        add     eax,edi                           ;AX = rhs of character
        cmp     clip.rcl_xLeft,eax
        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     eax,edx                           ;Next char starts at AX
        mov     edi,clip.rcl_xLeft
        cmp     edi,eax
        jl      abcl_dummy_is_visible            ;Some part of dummy char became visible
        xchg    edi,eax                           ;Set start of next character

abcl_see_if_next:

        or      ecx,ecx
        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.rcl_xLeft, and shorten
;**       the width of the dummy character appropriately.
;*/


abcl_dummy_is_visible:

        xchg    eax,edx                           ;Set DX = # pixels in dummy
        sub     edx,edi
        xor     eax,eax                           ;Show no real character
        jmp     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     eax,edi                           ;Restore width of the character
        push    esi
        mov     esi,pFont

        ASSUME  ebx:PTR FONT_ENTRIES

        mov     ebx,[esi].fsCharOffset[ebx].fe_dBits
        pop     esi
        add     ebx,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    edx                               ;Save extra pixels to be added
        mov     edx,clip.rcl_xLeft
        sub     edx,edi                           ;Compute bits until we're visible
        je      abcl_save_first                  ;Starts on clip edge
        sub     edx,8                             ;Is current byte visible?
        jl      abcl_have_vis_start              ;  Yes

abcl_step_clipped_char:

        sub     eax,8                             ;Shorten the width of the character
        add     edi,8                             ;Move current position right
        add     bx,lfd.font_height               ;Move to next column of character
        sub     edx,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     edx,clip.rcl_xLeft
        xor     edx,edi
        and     edx,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     edx                               ;Restore extra pixels

abcl_all_done:

        jmp     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     edx,edx                           ;Zero extra pels so far
        lodsd                                     ;Get this char's offset
        add     eax,eax                           ;*2
        mov     ebx,eax
        add     eax,eax                           ;*4
        add     eax,eax                           ;*8
        add     ebx,eax                           ;*10

        .errnz  size ABC_FONT_ENTRIES - 10

        dec     ecx                               ;If last character, don't try and
        jz      abc_have_nexts_a_space           ;  load next char's "a" space
        mov     eax,DWORD PTR [esi]
        add     eax,eax                           ;*2
        mov     edx,eax
        add     eax,eax                           ;*4
        add     eax,eax                           ;*8
        add     eax,edx                           ;*10

        .errnz  size ABC_FONT_ENTRIES - 10

        xchg    eax,ebx
        mov     edx,pFont

        ASSUME  ebx:PTR ABC_FONT_ENTRIES

        movzx   edx,[edx].fsCharOffset[ebx].abc_a_space
        xchg    eax,ebx

        public  abc_have_nexts_a_space

abc_have_nexts_a_space::

        push    esi
        mov     esi,pFont
        movzx   eax,[esi].fsCharOffset[ebx].abc_b_space
        add     dx,[esi].fsCharOffset[ebx].abc_c_space
        add     edx,char_extra
        mov     ebx,[esi].fsCharOffset[ebx].abc_fe_dBits
        pop     esi
        add     ebx,amt_clipped_on_top           ;Adjust pointer for any clipping
        push    ebx
        test    accel,HAVE_WIDTH_VECT
        jz      abc_have_width
        mov     ebx,lp_dx
        ;movzx  edx,word ptr [ebx]
        ;inc    ebx
        ;inc    ebx
        ;@DMS 16color fix
        mov     edx,DWORD PTR [ebx]
        add     ebx,4
        mov     lp_dx,ebx
        sub     edx,eax                           ;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      edx,edx
        jge     abc_adj_is_ok
        add     edx,eax                           ;Don't allow the backwards step
        sbb     ebx,ebx                           ;  to go beyond the start of this
        and     edx,ebx                           ;  character
        sub     edx,eax

abc_adj_is_ok:

        pop     ebx                               ;Restore bits offset

        public  abc_clip_enters_here

abc_clip_enters_here::

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

abc_have_what_fits:

        sub     edx,eax                           ;DX = extra for the dummy character

abc_have_entire_width:

        add     eax,ebx                           ;Set number of pixels to use in char
        pop     ebx

        public  abc_have_adj_width

abc_have_adj_width::

        mov     num_null_pixels,edx              ;Save number of dummy pixels
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If character is less than 8 bits
        jbe     abc_width_ok                      ;  wide, push it's data

abc_still_wide:

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

abc_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits
        mov     edx,num_null_pixels

abc_check_dummy:

        xchg    eax,edx                           ;Just incase we go backwards
        or      eax,eax
        jz      abc_see_if_next                  ;No pixels for justification
        jl      abc_going_back
        mov     ebx,null_char_offset
        mov     edx,edi                           ;Compute phase
        and     dl,7
        add     edi,eax                           ;DI = next char's X position
        cmp     edi,clip.rcl_xRight
        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     eax,8                             ;If dummy is less than 8 bits
        jbe     abc_dummy_width_ok               ;  wide, push it's data

abc_dummy_still_wide:

        push    edx                               ;Push data showing phase,
        push    ebx                               ;  character is 8 wide, then
        sub     eax,8                             ;  create another character
        cmp     eax,8
        ja      abc_dummy_still_wide

abc_dummy_width_ok:

        mov     ah,dh
        push    eax                               ;Save width and phase
        push    ebx                               ;Save offset to bits

abc_see_if_next:

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

abc_all_done:

        mov     eax,edi                           ;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     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        xor     ecx,ecx                           ;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    edx                               ;If num_null_pixels < 0, then
        mov     edx,num_null_pixels              ;  a restart might be possible
        or      edx,edx
        jl      abc_might_need_restart           ;Might need a restart

abc_clipped_no_restart:

        mov     ecx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,ecx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,ecx                           ;Set new rhs
        xor     ecx,ecx                           ;Don't want any extra pixels
        mov     num_null_pixels,ecx
        pop     edx                               ;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.rcl_xRight, then a restart is needed.
;*/

abc_might_need_restart:

        or      ecx,ecx                           ;If last character
        jz      abc_clipped_no_restart           ;  then no restart needed
        add     edx,edi                           ;Compute next starting x
        sub     edx,clip.rcl_xRight
        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.rcl_xRight.  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,edx
        mov     edx,clip.rcl_xRight              ;Compute number of pixels
        sub     edi,edx                           ;  which have to be clipped
        sub     eax,edi                           ;Set new character width
        mov     edi,edx                           ;Set new rhs
        pop     edx
        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     eax,edi                           ;Set position of next character
        jmp     build_ret_addr



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

abc_restart:

        mov     eax,edi
        jmp     build_ret_addr

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


        public  pad_left_hand_side

pad_left_hand_side::

        mov     eax,edi                           ;Get starting x coordinate
        and     eax,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     ebx,edi
        sub     ebx,o_rect.rcl_xLeft
        jle     plhs_all_done                     ;Cannot add any.  Darn
        smin_ax ebx                              ;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     edx,edi                   ;DI = start x = text_bbox.rcl_xLeft
        sub     edx,eax                           ;Set new lhs of text bounding box
        mov     current_lhs,edx
        mov     ah,dl                             ;Set phase (x coordinate) of char
        and     ah,7
        pop     edx
        push    eax                               ;Width and phase of null character
        push    null_char_offset                 ;Offset in font of null character
        jmp     edx

plhs_all_done:

        ret

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


        public  pad_right_hand_side

pad_right_hand_side::

        mov     eax,edi                           ;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     ebx
        push    eax                               ;Width and phase of null character
        push    null_char_offset                 ;Offset in font of null character
        push    ebx
        movzx   eax,al                            ;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     ebx,o_rect.rcl_xRight            ;Compute distance from where I am to
        sub     ebx,edi                           ;  where opaque rectangle ends
        jle     prhs_have_rhs                     ;Opaque rect is left of text end
        smin_ax ebx                              ;Compute amount to move rhs

prhs_new_rhs:

        add     edi,eax                           ;Slide rhs right

prhs_have_rhs:

        ret

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


        public  process_stack_data

process_stack_data::

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

        mov     edi,lp_surface                    ;--> destination surface
        mov     bl,excel
        test    bl,IS_DEVICE                      ;Only preprocess if this is
        jz      psd_pp_done                       ;  the EGA


;/*
;**following destination is device
;*/

        call    ppsd_color
        ret

psd_pp_done:
        cmp     bitmap_type,8
        jne     do_mono_bitmap_char
        call    ppsd_color
        ret
do_mono_bitmap_char:
        mov     eax,text_bbox.rcl_yBottom        ;Compute Y component of the string
        mul     next_scan
        add     edi,eax
        add     edi,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     ebx,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     ebx,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:

;BEGIN           

        mov     edx,buffer              ;Make sure we don't go off end of stack
        sub     edx,esp
        ja      @f
        jmp     psd_exit
@@:

;/*
;**WARNING: If any additional PUSHes or POPs are added between the label
;**         PROCESS_STACK_DATA and here, the constant below must change and
;**         the SUB must be uncommented.  As it is, the SUB is unnecessary because
;**         anything less than 8 will be thrown out in the SHR instruction.
;**         Do not take the below SUB instruction out of the code.  Leave it here
;**         so nobody else will have to debug this problem.
;**        sub     edx,4                   ;Return address is on the stack
;*/

        shr     edx,3                   ;EDX now = number of chars left on stack after the current one
        .errnz  (size frame_data) - 8
        mov     esi,7                   ;Maximum number of characters to process in one loop
        mov     ah,7                    ;Assume maximum case
        cmp     esi,edx
        jle     @f
        mov     ah,dl
@@:                                     ;AH now has maximum loop count - 1

;END           

        xor     esi,esi                           ;Dispatch table index
        mov     edx,ebp                           ;Save frame pointer
        mov     ebp,buffer                        ;--> next character's data

        ASSUME  ebp:PTR frame_data

        movzx   ecx,word ptr [ebp].fd_width   ;CH = X position, CL = width

        errnz   frame_data.fd_phase-frame_data.fd_width-1

        add     ch,cl                             ;CH = next char's start bit position

;BEGIN           

        push    ebp
@@:
        cmp     ch,al
        ja      psd_have_more_than_enough
        je      psd_have_exact_fit

        dec     ah
        js      psd_have_exact_fit      ;What other choice do we have?
        inc     esi
        sub     ebp,(size frame_data)
        add     ch,[ebp].fd_width
        jmp     @b

;END           


psd_have_exact_fit:
        pop     ebp                               ;          
        mov     ecx,esi                           ;# of source character involved
        shl     esi,2                             ;Compute index into dispatch table
        mov     ebx,DWORD PTR [ebx][esi] ;Get address of drawing function
        shl     esi,1

        errnz   <(size frame_data) - 8>

        neg     esi                               ;Going backwards
        lea     eax,[ebp][-(size frame_data)][esi]
        xchg    ebp,edx                           ;Restore frame pointer
        mov     buffer,eax                        ;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     eax,clipped_font_height

        call    ebx                               ;Invoke drawing routine

        mov     al,8                              ;First doesn't cross byte boundary
        mov     ebx,non_clipped_table            ;No clipping required
        mov     ss_clip_mask,0FFh
        dec     inner_byte_count
        jg      psd_collect_chars
        jmp     psd_see_about_last

psd_have_more_than_enough:
        pop     ebp                               ;          
        mov     ecx,esi                           ;# of source character involved
        shl     esi,2                             ;Compute index into dispatch table
        mov     ebx,DWORD PTR [ebx][esi] ;Get address of drawing function
        shl     esi,1

        errnz   <(size frame_data) - 8>

        neg     esi                               ;Going backwards
        lea     eax,[ebp][esi]
        xchg    ebp,edx                           ;Restore frame pointer
        mov     buffer,eax                        ;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     eax,clipped_font_height

        call    ebx                               ;Invoke drawing routine

        mov     al,16                             ;First crosses byte boundary
        mov     ebx,non_clipped_table            ;No clipping required
        mov     ss_clip_mask,0FFh
        dec     inner_byte_count
        jle     psd_see_about_last
        jmp     psd_collect_chars


psd_see_about_last:

        and     excel,not RES_EGA_INNER ;Don't restore ega after partial byte
        xor     ecx,ecx                           ;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     ebx,clipped_table                ;Must use the clipped table
        jmp     psd_collect_chars

psd_exit:

        ret


;/*
;** Code for device character string output
;*/

        public  ppsd_color

ppsd_color::
        mov     eax,pFont
        mov     esi,eax
        mov     eax,buffer
        sub     eax,4
        mov     buffer,eax

        xor     eax,eax
        mov     ah,left_clip_mask
        mov     al,right_clip_mask
        call    convert_mask_to_count

        mov     al,colorphase
        mov     ss_clip_mask,al

;/*
;**calculate starting address di and set bank
;*/

        push    ecx
        mov     eax,text_bbox.rcl_yBottom        ;Compute Y component of the string
        cmp     bitmap_type,8
        jne     ppsdco_device_1
        mul     next_scan                        ;use 1k scan line
        pop     ecx
        mov     edi,eax
        add     edi,scan_start                    ;Add delta into scan
        add     edi,lp_surface                   ;pVRAMInstance
        jmp     ppsdco_print_char
ppsdco_device_1:
        mov     ecx,next_scan                    ;1024
        mul     cx
        pop     ecx
        mov     edi,eax
        add     edi,scan_start                    ;Add delta into scan
        add     edi,pVRAMInstance

;/*
;**-----save correct bank
;*/

        mov     current_banks,dl
        mov     Origin_bank,dl
        call    set_bank_select

ppsdco_print_char:
        test    accel,IS_OPAQUE
        jz      draw_transp_color_char

        xor     ecx,ecx
        mov     edx,ebp                           ; Save frame pointer
        mov     ebp,buffer                        ; --> next character's data
        sub     ch,ch                             ; CH = phase
        mov     cl,byte ptr [ebp+4]              ;-4] ; CL = width
        sub     cl,ss_clip_mask         ; subtract the # of bits lost to SHL
        mov     ss_height,edi
        add     ss_height,ecx                     ;ss_height point to next char offset

        add     esi,dword ptr[ebp]               ;-8] ; SI --> FONT

;/*
;**
;** point the frame pointer to the next character
;**
;*/

        lea     eax,[ebp-8]                       ;.[-8(size frame_data)]
        mov     ebp,edx                           ; Restore frame pointer
        mov     buffer,eax                        ; Save new buffer pointer

;/*
;**
;** possibly clip the length of the next character
;**
;*/

        cmp     ecx,inner_byte_count
        jle     @F                                ; not clipped, continue on...
        mov     ecx,inner_byte_count

@@:
        xor     ebx,ebx
        mov     bl,bitmap_type
        mov     ss_phases,ebx
        mov     ebx,next_scan                    ;1024 ;ss_phases  ; lenght of map less char width
        mov     ebp,clipped_font_height          ; BP holds the font length



ifndef  JTUNE        ;IBMJ
        sub     ebx,ecx
endif  ;JTUNE        ;IBMJ
        mov     ss_next_scan,ebx                 ; holds offset to next scan line

;/*
;** Call the procedure with the following register variables
;**
;**    DS:      =  Font bits segment
;**    ES:DI  -->  Destination
;**    DX       =  Foreground/Background colors
;**    CL       =  Font width
;**    BP       =  Font length
;*/

        jcxz    @F
        xchg    edx,ss_colors                     ; load colors & save DX
        push    edx
        call    color_opaque_output
        pop     edx
        xchg    edx,ss_colors

@@:
        mov     ebp,edx                 ; restore the frame pointer
        mov     edi,ss_height                     ; point to the next character
        mov     eax,pFont
        mov     esi,eax

;/*
;**
;** check the list counter, & go for more...
;**
;*/

        mov     ss_clip_mask,ch                   ; flush the shift count
        cmp     bitmap_type,8
        je      ppsdco_device_2
        mov     dl,current_banks
        mov     Origin_bank,dl
        call    set_bank_select

ppsdco_device_2:
        sub     inner_byte_count,ecx
        jg      ppsdco_print_char
        ret

draw_transp_color_char:
        xor     ecx,ecx
        mov     edx,ebp                           ; Save frame pointer
        mov     ebp,buffer                        ; --> next character's data


        mov     cl,byte ptr [ebp+4]              ;-4] ; CL = width
        sub     cl,ss_clip_mask         ; subtract the # of bits lost to SHL
        mov     ss_height,edi
        add     ss_height,ecx                     ;ss_height point to next char offset

        add     esi,dword ptr[ebp]               ;-8] ; SI --> FONT


;/*
;** point the frame pointer to the next character
;*/

        lea     eax,[ebp-8]                       ;.[-8(size frame_data)]
        mov     ebp,edx                           ; Restore frame pointer
        mov     buffer,eax                        ; Save new buffer pointer

;/*
;** possibly clip the length of the next character
;*/

        cmp     ecx,inner_byte_count
        jle     @F                                ; not clipped, continue on...
        mov     ecx,inner_byte_count

@@:
        xor     ebx,ebx
        mov     bl,bitmap_type
        mov     ss_phases,ebx
        mov     ebx,next_scan                    ;1024 ;ss_phases  ; lenght of map less char width
        mov     al,accel
        mov     ebp,clipped_font_height          ; BP holds the font length
ifndef  JTUNE        ;IBMJ
        sub     ebx,ecx
endif  ;JTUNE        ;IBMJ
        mov     ss_next_scan,ebx                 ; holds offset to next scan line


;/*
;**
;** Call the procedure with the following register variables
;**
;**    DS:      =  Font bits segment
;**    ES:DI  -->  Destination
;**    DX       =  Foreground/Background colors
;**    CL       =  Font width
;**    AL       =  Accel Flags
;**    BP       =  Font length
;*/

        jcxz    @F
        xchg    edx,ss_colors                     ; load colors & save DX
        push    edx
        call    color_transp_output
        pop     edx
        xchg    edx,ss_colors
;
@@:
        mov     ebp,edx                 ; restore the frame pointer
        mov     edi,ss_height                     ; point to the next character
        mov     eax,pFont
        mov     esi,eax


;/*
;** check the list counter, & go for more...
;*/

        mov     ss_clip_mask,ch                   ; flush the shift count
        cmp     bitmap_type,8
        je      ppsdco_device_3
        mov     dl,current_banks
        mov     Origin_bank,dl
        call    set_bank_select

ppsdco_device_3:
        sub     inner_byte_count,ecx
        jg      ppsdco_print_char

        ret

        public  convert_mask_to_count

convert_mask_to_count::
        push    ebx

        xor     ebx,ebx
        mov     bl,ah                             ;get left first
        add     ebx,offset cnv_msk_table
        mov     ah,byte ptr cs:[ebx]
        xor     ebx,ebx
        mov     bl,al                             ;get right first
        add     ebx,offset cnv_msk_table
        mov     al,byte ptr cs:[ebx]
        add     al,ah
        xor     ebx,ebx
        mov     bl,al
        add     inner_byte_count,ebx

        pop     ebx
        ret

cnv_msk_table   label   byte
        db 0,1,0,2,0,0,0,3,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5
        db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6
        db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7
        db 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        db 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        db 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,0,6,0,7,8


ifndef JTUNE        ;IBMJ

;/*
;**
;** C O L O R _ O P A Q U E _ O U T P U T
;**
;** Assumed Entry Conditions:
;**          dl holds the foreground color
;**          dh holds the background color
;**       es:di ==> destination
;**       ds:si ==> font data
;**          cl holds the character width
;**          bp holds the character length
;**
;** Exit Conditions:
;**       CH = 0, CL holds the width
;**       BP = 0
;**       AX,BX,DX,SI,DI modified
;**
;*/

STOSBDI macro                ;JMW
        mov     [edi],al     ;JMW
        inc     di           ;JMW
        jnz     @f           ;JMW
        dec     di           ;JMW
        push    eax          ;JMW
        mov     eax,1        ;JMW
        call    Update_Bank  ;JMW
        pop     eax          ;JMW
@@:                          ;JMW
endm                         ;JMW

pcpou_exit:
        pop     ecx
        ret

pcpou_ones:
        mov     al,dl
        mov     ah,ch
        sub     cl,cl
        xchg    cl,ch
        cmp     ss_phases,8        ;@MRC - Do not update banks in Memory DCs
        jne     pcpou_l1           ;@MRC
        rep     stosb        ;@DMS ;@MRC
        jmp     pcpou_out1         ;@MRC
pcpou_l1:
        STOSBDI              ;@DMS
        loop    pcpou_l1     ;@DMS
pcpou_out1:                        ;@MRC

        dec     bp
        jz      pcpou_exit
        mov     ch,ah
        jmp     pcpou_xx1

pcpou_zeros:
        mov     al,dh
        mov     ah,ch
        sub     cl,cl
        xchg    cl,ch
        cmp     ss_phases,8        ;@MRC - Do not update banks in Memory DCs 
        jne     pcpou_l2           ;@MRC
        rep     stosb        ;@DMS ;@MRC
        jmp     pcpou_out2         ;@MRC
pcpou_l2:
        STOSBDI              ;@DMS
        loop    pcpou_l2     ;@DMS
pcpou_out2:                        ;@MRC

        dec     bp
        jz      pcpou_exit
        mov     ch,ah

pcpou_xx1:
        cmp     ss_phases,8
        je      pcpou_device_1

        push    eax
        mov     eax,ss_next_scan
        call    Update_Bank
        pop     eax
        jmp     pcpou_xx2

pcpou_device_1:
        add     edi,ss_next_scan                  ; skip to next scan line
;
pcpou_xx2:

STOSBDI macro                ;JMW
        local   is_device    ;          
                             ;          
        cmp     ss_phases,8  ;          
        jne     is_device    ;          
        stosb                ;          
        jmp     @f           ;          
is_device:                   ;          
        mov     [edi],al     ;JMW
        inc     di           ;JMW
        jnz     @f           ;JMW
        dec     di           ;JMW
        push    eax          ;JMW
        mov     eax,1        ;JMW
        call    Update_Bank  ;JMW
        pop     eax          ;JMW
@@:                          ;JMW
endm                         ;JMW

        public  pcopq_inner_loop

pcopq_inner_loop::

        lodsb

        mov     cl,ss_clip_mask
        shl     al,cl

        cmp     al,0
        jz      pcpou_zeros                       ; zero special case
        cmp     al,0ffh
        jz      pcpou_ones                        ; ones special case

        mov     cl,al
        jmp     ebx

pcopq_draw_b0:
        shl     cl,1
        jnc     pcopq_draw_b0_NC
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b1:
        shl     cl,1
        jnc     pcopq_draw_b1_NC
pcopq_draw_b1_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b2:
        shl     cl,1
        jnc     pcopq_draw_b2_NC
pcopq_draw_b2_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b3:
        shl     cl,1
        jnc     pcopq_draw_b3_NC
pcopq_draw_b3_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b4:
        shl     cl,1
        jnc     pcopq_draw_b4_NC
pcopq_draw_b4_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b5:
        shl     cl,1
        jnc     pcopq_draw_b5_NC
pcopq_draw_b5_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b6:
        shl     cl,1
        jnc     pcopq_draw_b6_NC
pcopq_draw_b6_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

pcopq_draw_b7:
        shl     cl,1
        jnc     pcopq_draw_b7_NC
pcopq_draw_b7_CY:
        mov     al,dl                             ; foreground output
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

        dec     bp
        jnz     pcpou_xx1
        pop     ecx
        ret

pcopq_draw_b0_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b1_CY

pcopq_draw_b1_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b2_CY

pcopq_draw_b2_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b3_CY

pcopq_draw_b3_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b4_CY

pcopq_draw_b4_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b5_CY

pcopq_draw_b5_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b6_CY

pcopq_draw_b6_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS
        shl     cl,1
        jc      pcopq_draw_b7_CY

pcopq_draw_b7_NC:
        mov     al,dh                             ; background
        ;stosb               ;@DMS
        STOSBDI              ;@DMS

        dec     bp
        jnz     pcpou_xx1
        pop     ecx
        ret


        public  color_opaque_output

color_opaque_output::
        movzx   ecx,cl
        push    ecx
        mov     ebx,ecx
        sub     ecx,8
        neg     ecx
        mov     ecx,cs:pcolo_opq_draw[ecx*4]
        xchg    ecx,ebx
        mov     ch,cl
        jmp     pcopq_inner_loop

pcolo_opq_draw   label   dword
        dd      pcopq_draw_b0
        dd      pcopq_draw_b1
        dd      pcopq_draw_b2
        dd      pcopq_draw_b3
        dd      pcopq_draw_b4
        dd      pcopq_draw_b5
        dd      pcopq_draw_b6
        dd      pcopq_draw_b7

STOSBDI macro                ;JMW
        local   is_device    ;          
                             ;          
        cmp     ss_phases,8  ;          
        jne     is_device    ;          
        stosb                ;          
        jmp     @f           ;          
is_device:                   ;          
        mov     [edi],al     ;JMW
        inc     di           ;JMW
        jnz     @f           ;JMW
        dec     di           ;JMW
        push    eax          ;JMW
        mov     eax,1        ;JMW
        call    Update_Bank  ;JMW
        pop     eax          ;JMW
@@:                          ;JMW
endm                         ;JMW

ifdef  JFIX        ;IBMJ
ORSBDI  macro                ;MRC
        local   is_device    ;          
                             ;          
        cmp     ss_phases,8  ;          
        jne     is_device    ;          
        or      [edi],al     ;          
        inc     edi          ;          
        jmp     @f           ;          
is_device:
        or      [edi],al     ;MRC
        inc     di           ;MRC
        jnz     @f           ;MRC
        dec     di           ;MRC
        push    eax          ;MRC
        mov     eax,1        ;MRC
        call    Update_Bank  ;MRC
        pop     eax          ;MRC
@@:                          ;MRC
endm                         ;MRC
endif ;JFIX        ;IBMJ

XORSBDI macro                ;MRC
        local   is_device    ;          
                             ;          
        cmp     ss_phases,8  ;          
        jne     is_device    ;          
        xor     [edi],al     ;          
        inc     edi          ;          
        jmp     @f           ;          
is_device:
        xor     [edi],al     ;MRC
        inc     di           ;MRC
        jnz     @f           ;MRC
        dec     di           ;MRC
        push    eax          ;MRC
        mov     eax,1        ;MRC
        call    Update_Bank  ;MRC
        pop     eax          ;MRC
@@:                          ;MRC
endm                         ;MRC


INCDI macro                  ;JMW
        local   is_device    ;          
                             ;          
        cmp     ss_phases,8  ;          
        jne     is_device    ;          
        inc     edi          ;          
        jmp     @f           ;          
is_device:                   ;          
        inc     di           ;JMW
        jnz     @f           ;JMW
        dec     di           ;JMW
        push    eax          ;JMW
        mov     eax,1        ;JMW
        call    Update_Bank  ;JMW
        pop     eax          ;JMW
@@:                          ;JMW
endm                         ;JMW


;/*
;**
;** T R A N S P _ L O O P _ C O N T R O L
;**
;** Assumed Entry Conditions:
;**          dl holds the foreground color
;**          dh holds the background color
;**       es:di ==> destination
;**       ds:si ==> font data
;**          cl holds the character width
;**          bp holds the character length
;**
;** Exit Conditions:
;**       CH = 0, CL holds the width
;**       BP = 0
;**       AX,BX,DX,SI,DI modified
;**
;*/

pctra_exit:
        pop     ecx
        ret

pctra_ones:
        mov     al,dl           ; get the foreground color & print it.
;JMW        stosb                   ; taking advantage of hardware delays.
        STOSBDI              ;JMW
        mov     ah,ch           ; while the hardware swallows that last byte,
        mov     cl,ch           ; we can perform some overhead...
        dec     cl              ; reduce count by that one stosb
        jz      no_rep          ; skip if now null
        sub     ch,ch

        cmp     ss_phases,8  ;JMW
        je      not_device   ;JMW
loop1:                       ;JMW
        STOSBDI              ;JMW
        loop    loop1        ;JMW
        jmp     no_rep       ;JMW
not_device:                  ;JMW

        rep     stosb
no_rep:
        mov     ch,ah
        mov     al,ah

        cmp     ss_phases,8  ;JMW
        jne     @f           ;JMW
        movsx   eax,al  ;          
        sub     edi,eax ;          
        jmp     not_device2  ;JMW
@@:                          ;JMW
        cbw                  ;JMW
        sub     di,ax        ;JMW
        jnc     not_device2  ;JMW
        add     di,ax        ;JMW
        and     eax,0ffffh   ;JMW
        neg     eax          ;JMW
        call    Update_Bank  ;JMW
not_device2:                 ;JMW
;
pctra_zeros:
        mov     al,ch

        cmp     ss_phases,8  ;JMW
        jne     @f           ;JMW
        movsx   eax,al  ;          
        add     edi,eax ;          
        jmp     not_device1  ;JMW
@@:                          ;JMW
        cbw                  ;JMW
        add     di,ax        ;JMW
        jnc     not_device1  ;JMW
        sub     di,ax        ;JMW
        movsx   eax,ax       ;JMW
        call    Update_Bank  ;JMW
not_device1:                 ;JMW

        dec     bp
        jz      pctra_exit
        mov     cl,al

pctra_xx1:
        cmp     ss_phases,8
        je      pctra_device_1
        push    eax
        mov     eax,ss_next_scan
        call    Update_Bank
        pop     eax
        jmp     pctra_xx2

pctra_device_1:

        add     edi,ss_next_scan                ; skip to next scan line
;
pctra_xx2:

        public  pctra_inner_loop

pctra_inner_loop::
        lodsb

        mov     cl,ss_clip_mask
        shl     al,cl

        cmp     al,0
        jz      pctra_zeros                       ; zero special case

        ;           Took the following lines out because
        ;           easier than special casing XOR at this
        ;           level.
        ;           cmp     al,0ffh
        ;           jz      pctra_ones           ; ones special case

        mov     cl,al
        mov     al,dl
        jmp     ebx


pctra_draw_b0:
        shl     cl,1
        jnc     pctra_draw_b0_NC
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b1:
        shl     cl,1
        jnc     pctra_draw_b1_NC
pctra_draw_b1_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b2:
        shl     cl,1
        jnc     pctra_draw_b2_NC
pctra_draw_b2_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b3:
        shl     cl,1
        jnc     pctra_draw_b3_NC
pctra_draw_b3_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b4:
        shl     cl,1
        jnc     pctra_draw_b4_NC
pctra_draw_b4_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b5:
        shl     cl,1
        jnc     pctra_draw_b5_NC
pctra_draw_b5_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b6:
        shl     cl,1
        jnc     pctra_draw_b6_NC
pctra_draw_b6_CY:
        STOSBDI              ;JMW
;JMW        stosb

pctra_draw_b7:
        shl     cl,1
        jnc     pctra_draw_b7_NC
pctra_draw_b7_CY:
        STOSBDI              ;JMW
;JMW        stosb

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret


pctra_draw_b0_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b1_CY

pctra_draw_b1_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b2_CY

pctra_draw_b2_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b3_CY

pctra_draw_b3_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b4_CY

pctra_draw_b4_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b5_CY

pctra_draw_b5_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b6_CY

pctra_draw_b6_NC:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b7_CY

pctra_draw_b7_NC:
        INCDI                ;JMW
;JMW    inc     di

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret

ifdef  JFIX        ;IBMJ
pctra_draw_b0_or:
        shl     cl,1
        jnc     pctra_draw_b0_NC_OR
        ORSBDI

pctra_draw_b1_or:
        shl     cl,1
        jnc     pctra_draw_b1_NC_OR
pctra_draw_b1_CY_OR:
        ORSBDI

pctra_draw_b2_or:
        shl     cl,1
        jnc     pctra_draw_b2_NC_OR
pctra_draw_b2_CY_OR:
        ORSBDI

pctra_draw_b3_or:
        shl     cl,1
        jnc     pctra_draw_b3_NC_OR
pctra_draw_b3_CY_OR:
        ORSBDI

pctra_draw_b4_or:
        shl     cl,1
        jnc     pctra_draw_b4_NC_OR
pctra_draw_b4_CY_OR:
        ORSBDI

pctra_draw_b5_or:
        shl     cl,1
        jnc     pctra_draw_b5_NC_OR
pctra_draw_b5_CY_OR:
        ORSBDI

pctra_draw_b6_or:
        shl     cl,1
        jnc     pctra_draw_b6_NC_OR
pctra_draw_b6_CY_OR:
        ORSBDI

pctra_draw_b7_or:
        shl     cl,1
        jnc     pctra_draw_b7_NC_OR
pctra_draw_b7_CY_OR:
        ORSBDI

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret


pctra_draw_b0_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b1_CY_OR

pctra_draw_b1_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b2_CY_OR

pctra_draw_b2_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b3_CY_OR

pctra_draw_b3_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b4_CY_OR

pctra_draw_b4_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b5_CY_OR

pctra_draw_b5_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b6_CY_OR

pctra_draw_b6_NC_OR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b7_CY_OR

pctra_draw_b7_NC_OR:
        INCDI                ;JMW
;JMW    inc     di

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret
endif ;JFIX        ;IBMJ

pctra_draw_b0_xor:
        shl     cl,1
        jnc     pctra_draw_b0_NC_XOR
        XORSBDI

pctra_draw_b1_xor:
        shl     cl,1
        jnc     pctra_draw_b1_NC_XOR
pctra_draw_b1_CY_XOR:
        XORSBDI

pctra_draw_b2_xor:
        shl     cl,1
        jnc     pctra_draw_b2_NC_XOR
pctra_draw_b2_CY_XOR:
        XORSBDI

pctra_draw_b3_xor:
        shl     cl,1
        jnc     pctra_draw_b3_NC_XOR
pctra_draw_b3_CY_XOR:
        XORSBDI

pctra_draw_b4_xor:
        shl     cl,1
        jnc     pctra_draw_b4_NC_XOR
pctra_draw_b4_CY_XOR:
        XORSBDI

pctra_draw_b5_xor:
        shl     cl,1
        jnc     pctra_draw_b5_NC_XOR
pctra_draw_b5_CY_XOR:
        XORSBDI

pctra_draw_b6_xor:
        shl     cl,1
        jnc     pctra_draw_b6_NC_XOR
pctra_draw_b6_CY_XOR:
        XORSBDI

pctra_draw_b7_xor:
        shl     cl,1
        jnc     pctra_draw_b7_NC_XOR
pctra_draw_b7_CY_XOR:
        XORSBDI

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret


pctra_draw_b0_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b1_CY_XOR

pctra_draw_b1_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b2_CY_XOR

pctra_draw_b2_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b3_CY_XOR

pctra_draw_b3_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b4_CY_XOR

pctra_draw_b4_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b5_CY_XOR

pctra_draw_b5_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b6_CY_XOR

pctra_draw_b6_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di
        shl     cl,1
        jc      pctra_draw_b7_CY_XOR

pctra_draw_b7_NC_XOR:
        INCDI                ;JMW
;JMW    inc     di

        dec     bp
        jnz     pctra_xx1
        pop     ecx
        ret


        public  color_transp_output

color_transp_output::
        movzx   ecx,cl
        push    ecx
        mov     ebx,ecx
        sub     ecx,8
        neg     ecx
ifdef  JFIX        ;IBMJ
 test al,IS_OR_TEXT
 jnz cto_or
endif ;JFIX        ;IBMJ
        test    al,IS_XOR_TEXT
        jnz     cto_xor
        mov     ecx,cs:pcolo_tra_draw[ecx*4]     ;2]
cto_xor_ret:
        xchg    ecx,ebx
        mov     ch,cl
        jmp     pctra_inner_loop
ifdef  JFIX        ;IBMJ
cto_or:
 mov ecx,cs:pcolo_tra_draw_or[ecx*4]      ;2]
 jmp cto_xor_ret
endif ;JFIX        ;IBMJ
cto_xor:
        mov     ecx,cs:pcolo_tra_draw_xor[ecx*4]     ;2]
        jmp     cto_xor_ret

pcolo_tra_draw   label   dword
        dd      pctra_draw_b0
        dd      pctra_draw_b1
        dd      pctra_draw_b2
        dd      pctra_draw_b3
        dd      pctra_draw_b4
        dd      pctra_draw_b5
        dd      pctra_draw_b6
        dd      pctra_draw_b7

ifdef  JFIX        ;IBMJ
pcolo_tra_draw_or    label   dword
        dd      pctra_draw_b0_or
        dd      pctra_draw_b1_or
        dd      pctra_draw_b2_or
        dd      pctra_draw_b3_or
        dd      pctra_draw_b4_or
        dd      pctra_draw_b5_or
        dd      pctra_draw_b6_or
        dd      pctra_draw_b7_or
endif ;JFIX        ;IBMJ

pcolo_tra_draw_xor   label   dword
        dd      pctra_draw_b0_xor
        dd      pctra_draw_b1_xor
        dd      pctra_draw_b2_xor
        dd      pctra_draw_b3_xor
        dd      pctra_draw_b4_xor
        dd      pctra_draw_b5_xor
        dd      pctra_draw_b6_xor
        dd      pctra_draw_b7_xor

else  ;JTUNE        ;IBMJ
;----------------------------Private-Routine----------------------------;
; color_opaque_output
;
; Entry:
; DL  = foreground color
; DH  = background color
;       EDI = screen/memory destination
;       ESI = font pattern
; Returns:
;       CH = 0
; BP = 0
; Registers Destroyed:
; EAX,EBX,EDX,ESI,EDI
; Registers Preserved:
; CL
; calls:
; History:
;  Fri 02-Jul-1993 18:00:00 -by-  Hidemasa Muta [JL25345@YMTVM1.vnet.ibm.com]
; Created.
;-----------------------------------------------------------------------;

 public color_opaque_output
color_opaque_output::

 cmp LastFgBg,dx
 je @F
 call pcopq_create_tables
 mov LastFgBg,dx
@@:
 mov ch,cl
 mov cl,ss_clip_mask
 mov eax,0ffh
 shl al,cl
 mov ClipAndMask,eax
 mov al,ch
 mov eax,cs:pcolo_opq_draw[eax*4]
 mov edx,ss_next_scan
 jmp eax

pcolo_opq_draw LABEL DWORD
 DWORD 0
 DWORD pcopq_1
 DWORD pcopq_2
 DWORD pcopq_3
 DWORD pcopq_4
 DWORD pcopq_5
 DWORD pcopq_6
 DWORD pcopq_7
 DWORD pcopq_8

pcopq_1:
 and ClipAndMask,80h   ; upper 1 bits pattern
pcopq_1_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov al,byte ptr Upper4PPTable[eax] ; 1 bits -> 1 packed pixel
 mov byte ptr [edi],al  ; store 1 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_1_change_bank
 dec bp
 jnz pcopq_1_loop
 movzx ecx,ch
 ret
pcopq_1_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_1_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_1_loop
 movzx ecx,ch
 ret

pcopq_2:
 and ClipAndMask,0c0h  ; upper 2 bits pattern
pcopq_2_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov ax,word ptr Upper4PPTable[eax] ; 2 bits -> 2 packed pixel
 mov word ptr [edi],ax  ; store 2 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_2_change_bank
 dec bp
 jnz pcopq_2_loop
 movzx ecx,ch
 ret
pcopq_2_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_2_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_2_loop
 movzx ecx,ch
 ret

pcopq_3:
 and ClipAndMask,0e0h  ; upper 3 bits pattern
pcopq_3_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov word ptr [edi],ax  ; store 2 packed pixel
 shr eax,16
 mov byte ptr [edi+2],al  ; store 1 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_3_change_bank
 dec bp
 jnz pcopq_3_loop
 movzx ecx,ch
 ret
pcopq_3_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_3_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_3_loop
 movzx ecx,ch
 ret

pcopq_4:
 and ClipAndMask,0f0h  ; upper 4 bits pattern
pcopq_4_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi],eax  ; store 4 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_4_change_bank
 dec bp
 jnz pcopq_4_loop
 movzx ecx,ch
 ret
pcopq_4_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_4_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_4_loop
 movzx ecx,ch
 ret

pcopq_5:
pcopq_5_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov ebx,eax
 and al,0f0h    ; upper 4 bits pattern
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi],eax  ; store 4 packed pixel
 and bl,08h    ; lower 1 bits pattern
 mov bl,byte ptr Lower4PPTable[ebx*4] ; 1 bits -> 1 packed pixel
 mov byte ptr [edi+4],bl  ; store 1 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_5_change_bank
 dec bp
 jnz pcopq_5_loop
 movzx ecx,ch
 ret
pcopq_5_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_5_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_5_loop
 movzx ecx,ch
 ret

pcopq_6:
pcopq_6_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov ebx,eax
 and al,0f0h    ; upper 4 bits pattern
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi],eax  ; store 4 packed pixel
 and bl,0ch    ; lower 2 bits pattern
 mov bx,word ptr Lower4PPTable[ebx*4] ; 2 bits -> 2 packed pixel
 mov word ptr [edi+4],bx  ; store 2 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_6_change_bank
 dec bp
 jnz pcopq_6_loop
 movzx ecx,ch
 ret
pcopq_6_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_6_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_6_loop
 movzx ecx,ch
 ret

pcopq_7:
pcopq_7_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov ebx,eax
 and al,0f0h    ; upper 4 bits pattern
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi],eax  ; store 4 packed pixel
 and bl,0eh    ; lower 3 bits pattern
 mov ebx,dword ptr Lower4PPTable[ebx*4] ; 4 bits -> 4 packed pixel
 mov word ptr [edi+4],bx  ; store 2 packed pixel
 shr ebx,16
 mov byte ptr [edi+6],bl  ; store 1 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_7_change_bank
 dec bp
 jnz pcopq_7_loop
 movzx ecx,ch
 ret
pcopq_7_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_7_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_7_loop
 movzx ecx,ch
 ret

pcopq_8:
pcopq_8_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 mov ebx,eax
 and al,0f0h    ; upper 4 bits pattern
 mov eax,dword ptr Upper4PPTable[eax] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi],eax  ; store 4 packed pixel
 and bl,0fh    ; lower 4 bits pattern
 mov ebx,dword ptr Lower4PPTable[ebx*4] ; 4 bits -> 4 packed pixel
 mov dword ptr [edi+4],ebx  ; store 4 packed pixel
 add di,dx    ; to the next scanline
 jc pcopq_8_change_bank
 dec bp
 jnz pcopq_8_loop
 movzx ecx,ch
 ret
pcopq_8_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pcopq_8_loop
 movzx ecx,ch
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pcopq_8_loop
 movzx ecx,ch
 ret


pcopq_create_tables:
 push edi
 mov ebx,offset Upper4PPTable
 mov edi,offset Lower4PPTable

 mov al,dh
 mov ah,dh
 shl eax,16
 mov al,dh
 mov ah,dh   ; BG:BG:BG:BG
 mov dword ptr [ebx],eax
 stosd

 mov al,dl
 ror eax,8   ; FG:BG:BG:BG
 mov dword ptr [ebx+10h],eax
 stosd

 ror eax,8   ; BG:FG:BG:BG
 mov dword ptr [ebx+20h],eax
 stosd

 mov ah,dl
 rol eax,8   ; FG:FG:BG:BG
 mov dword ptr [ebx+30h],eax
 stosd

 ror eax,16
 mov al,dh   ; BG:BG:FG:BG
 mov dword ptr [ebx+40h],eax
 stosd

 rol eax,16
 mov ah,dl   ; FG:BG:FG:BG
 mov dword ptr [ebx+50h],eax
 stosd

 ror eax,8
 xchg al,ah   ; BG:FG:FG:BG
 mov dword ptr [ebx+60h],eax
 stosd

 mov al,ah
 rol eax,8   ; FG:FG:FG:BG
 mov dword ptr [ebx+70h],eax
 stosd

 mov ah,al
 rol eax,8
 mov al,ah
 rol eax,8   ; BG:BG:BG:FG
 mov dword ptr [ebx+80h],eax
 stosd

 ror eax,8
 mov al,dl   ; FG:BG:BG:FG
 mov dword ptr [ebx+90h],eax
 stosd

 rol eax,16
 xchg ah,al   ; BG:FG:BG:FG
 mov dword ptr [ebx+0a0h],eax
 stosd

 mov ah,al
 ror eax,16   ; FG:FG:BG:FG
 mov dword ptr [ebx+0b0h],eax
 stosd

 mov al,ah
 ror eax,16   ; BG:BG:FG:FG
 mov dword ptr [ebx+0c0h],eax
 stosd

 ror eax,8
 mov ah,al   ; FG:BG:FG:FG
 mov dword ptr [ebx+0d0h],eax
 stosd

 rol eax,8   ; BG:FG:FG:FG
 mov dword ptr [ebx+0e0h],eax
 stosd

 rol eax,8
 mov al,ah   ; FG:FG:FG:FG
 mov dword ptr [ebx+0f0h],eax
 stosd

 pop edi
 ret


;----------------------------Private-Routine----------------------------;
; color_transp_output
;
; Entry:
;       AH  = attribute flags
; DL  = foreground color
; DH  = background color
;       EDI = screen/memory destination
;       ESI = font pattern
; Returns:
;       CH = 0
; BP = 0
; Registers Destroyed:
; EAX,EBX,EDX,ESI,EDI
; Registers Preserved:
; CL
; calls:
; History:
;  Fri 02-Jul-1993 20:00:00 -by-  Hidemasa Muta [JL25345@YMTVM1.vnet.ibm.com]
; Created.
;-----------------------------------------------------------------------;

 public color_transp_output
color_transp_output::

 test al,IS_OR_TEXT or IS_XOR_TEXT
 jz @F
 jmp pctra_ext
@@:
 mov ch,cl
 mov cl,ss_clip_mask
 mov eax,0ffh
 shl al,cl
 mov ClipAndMask,eax
 mov dh,dl
 movzx eax,ch
 push eax
 cmp ch,4
 ja pctra_5to8

pctra_1to4:
 mov eax,0ffh
 xchg cl,ch
 shl al,cl
 shr al,cl
 xchg cl,ch
 not al
 and ClipAndMask,eax  ; upper CH bits pattern
 mov ebx,ss_next_scan
pctra_1to4_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 shr al,2
 call cs:pcolo_tra_draw[eax]
 add di,bx
 jc pctra_1to4_change_bank
 dec bp
 jnz pctra_1to4_loop
 pop ecx
 ret
pctra_1to4_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pctra_1to4_loop
 pop ecx
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pctra_1to4_loop
 pop ecx
 ret

pctra_5to8:
 sub ch,4
 mov eax,0ffh
 xchg cl,ch
 shl al,cl
 shr al,cl
 xchg cl,ch
 not al
 shr al,4
 mov ch,al    ; lower N-4 bits mask
 mov ebx,ss_next_scan
 sub bx,4
pctra_5to8_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 push eax
 and al,0f0h    ; upper 4 bits pattern
 shr al,2
 call cs:pcolo_tra_draw[eax]
 add di,4
 pop eax
 and al,ch    ; lower N-4 bits pattern
 call cs:pcolo_tra_draw[eax*4]
 add di,bx
 jc pctra_5to8_change_bank
 dec bp
 jnz pctra_5to8_loop
 pop ecx
 ret
pctra_5to8_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pctra_5to8_loop
 pop ecx
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pctra_5to8_loop
 pop ecx
 ret

 public pctra_ext
pctra_ext::
 mov dh,al   ; al = IS_OR_TEXT or IS_XOR_TEXT
 and dh,IS_OR_TEXT or IS_XOR_TEXT
 shl dh,5
 .errnz IS_OR_TEXT -00000100b
 .errnz IS_XOR_TEXT-00000010b

 mov ch,cl
 mov cl,ss_clip_mask
 mov eax,0ffh
 shl al,cl
 mov ClipAndMask,eax
 movzx eax,ch
 push eax
 mov bh,dh   ; bh = OR, XOR offset
 mov dh,dl
 cmp ch,4
 ja pctra_ext_5to8

pctra_ext_1to4:
 mov eax,0ffh
 xchg cl,ch
 shl al,cl
 shr al,cl
 xchg cl,ch
 not al
 and ClipAndMask,eax  ; upper CL bits pattern
pctra_ext_1to4_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 shr al,2
 or al,bh   ; bh = OR, XOR offset
 call cs:pcolo_tra_draw[eax]
 add di,word ptr ss_next_scan
 jc pctra_ext_1to4_change_bank
 dec bp
 jnz pctra_ext_1to4_loop
 pop ecx
 ret
pctra_ext_1to4_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pctra_ext_1to4_loop
 pop ecx
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pctra_ext_1to4_loop
 pop ecx
 ret

pctra_ext_5to8:
 sub ch,4
 mov eax,0ffh
 xchg cl,ch
 shl al,cl
 shr al,cl
 xchg cl,ch
 not al
 shr al,4
 mov ch,al    ; lower N-4 bits mask
pctra_ext_5to8_loop:
 lodsb
 shl al,cl
 and eax,ClipAndMask
 push eax
 and al,0f0h    ; upper 4 bits pattern
 shr al,2
 or al,bh    ; bh = OR, XOR offset
 call cs:pcolo_tra_draw[eax]
 add di,4
 pop eax
 and al,ch    ; lower N-4 bits pattern
 shl al,2
 or al,bh    ; bh = OR, XOR offset
 call cs:pcolo_tra_draw[eax]
 sub di,4
 add di,word ptr ss_next_scan
 jc pctra_ext_5to8_change_bank
 dec bp
 jnz pctra_ext_5to8_loop
 pop ecx
 ret
pctra_ext_5to8_change_bank:
 cmp ss_phases,8
 jne @F
 add edi,10000h
 dec bp
 jnz pctra_ext_5to8_loop
 pop ecx
 ret
@@:
 xchg dl,Origin_bank
 inc dl
 call set_bank_select
 xchg dl,Origin_bank
 dec bp
 jnz pctra_ext_5to8_loop
 pop ecx
 ret

pcolo_tra_draw LABEL DWORD
 DWORD pctra_0
 DWORD pctra_8
 DWORD pctra_4
 DWORD pctra_c
 DWORD pctra_2
 DWORD pctra_a
 DWORD pctra_6
 DWORD pctra_e
 DWORD pctra_1
 DWORD pctra_9
 DWORD pctra_5
 DWORD pctra_d
 DWORD pctra_3
 DWORD pctra_b
 DWORD pctra_7
 DWORD pctra_f
 DWORD pctra_xor_0
 DWORD pctra_xor_8
 DWORD pctra_xor_4
 DWORD pctra_xor_c
 DWORD pctra_xor_2
 DWORD pctra_xor_a
 DWORD pctra_xor_6
 DWORD pctra_xor_e
 DWORD pctra_xor_1
 DWORD pctra_xor_9
 DWORD pctra_xor_5
 DWORD pctra_xor_d
 DWORD pctra_xor_3
 DWORD pctra_xor_b
 DWORD pctra_xor_7
 DWORD pctra_xor_f
 DWORD pctra_or_0
 DWORD pctra_or_8
 DWORD pctra_or_4
 DWORD pctra_or_c
 DWORD pctra_or_2
 DWORD pctra_or_a
 DWORD pctra_or_6
 DWORD pctra_or_e
 DWORD pctra_or_1
 DWORD pctra_or_9
 DWORD pctra_or_5
 DWORD pctra_or_d
 DWORD pctra_or_3
 DWORD pctra_or_b
 DWORD pctra_or_7
 DWORD pctra_or_f
 DWORD pctra_or_0
 DWORD pctra_or_8
 DWORD pctra_or_4
 DWORD pctra_or_c
 DWORD pctra_or_2
 DWORD pctra_or_a
 DWORD pctra_or_6
 DWORD pctra_or_e
 DWORD pctra_or_1
 DWORD pctra_or_9
 DWORD pctra_or_5
 DWORD pctra_or_d
 DWORD pctra_or_3
 DWORD pctra_or_b
 DWORD pctra_or_7
 DWORD pctra_or_f

pctra_0:
 ret
pctra_1:
 mov byte ptr [edi],dl
 ret
pctra_2:
 mov byte ptr [edi+1],dl
 ret
pctra_3:
 mov word ptr [edi],dx
 ret
pctra_4:
 mov byte ptr [edi+2],dl
 ret
pctra_5:
 mov byte ptr [edi],dl
 mov byte ptr [edi+2],dl
 ret
pctra_6:
 mov word ptr [edi+1],dx
 ret
pctra_7:
 mov word ptr [edi],dx
 mov byte ptr [edi+2],dl
 ret
pctra_8:
 mov byte ptr [edi+3],dl
 ret
pctra_9:
 mov byte ptr [edi],dl
 mov byte ptr [edi+3],dl
 ret
pctra_a:
 mov byte ptr [edi+1],dl
 mov byte ptr [edi+3],dl
 ret
pctra_b:
 mov word ptr [edi],dx
 mov byte ptr [edi+3],dl
 ret
pctra_c:
 mov word ptr [edi+2],dx
 ret
pctra_d:
 mov byte ptr [edi],dl
 mov word ptr [edi+2],dx
 ret
pctra_e:
 mov byte ptr [edi+1],dl
 mov word ptr [edi+2],dx
 ret
pctra_f:
 mov word ptr [edi],dx
 mov word ptr [edi+2],dx
 ret

pctra_xor_0:
 ret
pctra_xor_1:
 xor byte ptr [edi],dl
 ret
pctra_xor_2:
 xor byte ptr [edi+1],dl
 ret
pctra_xor_3:
 xor word ptr [edi],dx
 ret
pctra_xor_4:
 xor byte ptr [edi+2],dl
 ret
pctra_xor_5:
 xor byte ptr [edi],dl
 xor byte ptr [edi+2],dl
 ret
pctra_xor_6:
 xor word ptr [edi+1],dx
 ret
pctra_xor_7:
 xor word ptr [edi],dx
 xor byte ptr [edi+2],dl
 ret
pctra_xor_8:
 xor byte ptr [edi+3],dl
 ret
pctra_xor_9:
 xor byte ptr [edi],dl
 xor byte ptr [edi+3],dl
 ret
pctra_xor_a:
 xor byte ptr [edi+1],dl
 xor byte ptr [edi+3],dl
 ret
pctra_xor_b:
 xor word ptr [edi],dx
 xor byte ptr [edi+3],dl
 ret
pctra_xor_c:
 xor word ptr [edi+2],dx
 ret
pctra_xor_d:
 xor byte ptr [edi],dl
 xor word ptr [edi+2],dx
 ret
pctra_xor_e:
 xor byte ptr [edi+1],dl
 xor word ptr [edi+2],dx
 ret
pctra_xor_f:
 xor word ptr [edi],dx
 xor word ptr [edi+2],dx
 ret

pctra_or_0:
 ret
pctra_or_1:
 or byte ptr [edi],dl
 ret
pctra_or_2:
 or byte ptr [edi+1],dl
 ret
pctra_or_3:
 or word ptr [edi],dx
 ret
pctra_or_4:
 or byte ptr [edi+2],dl
 ret
pctra_or_5:
 or byte ptr [edi],dl
 or byte ptr [edi+2],dl
 ret
pctra_or_6:
 or word ptr [edi+1],dx
 ret
pctra_or_7:
 or word ptr [edi],dx
 or byte ptr [edi+2],dl
 ret
pctra_or_8:
 or byte ptr [edi+3],dl
 ret
pctra_or_9:
 or byte ptr [edi],dl
 or byte ptr [edi+3],dl
 ret
pctra_or_a:
 or byte ptr [edi+1],dl
 or byte ptr [edi+3],dl
 ret
pctra_or_b:
 or word ptr [edi],dx
 or byte ptr [edi+3],dl
 ret
pctra_or_c:
 or word ptr [edi+2],dx
 ret
pctra_or_d:
 or byte ptr [edi],dl
 or word ptr [edi+2],dx
 ret
pctra_or_e:
 or byte ptr [edi+1],dl
 or word ptr [edi+2],dx
 ret
pctra_or_f:
 or word ptr [edi],dx
 or word ptr [edi+2],dx
 ret

endif ;JTUNE        ;IBMJ

        page

;/***************************************************************************
;*
;* FUNCTION NAME = 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
;*
;**************************************************************************/

        public  set_ega_opaque_mode

set_ega_opaque_mode::

        mov     dx,EGA_BASE + SEQ_DATA
        mov     al,MM_ALL
        out     dx,al
        mov     eax,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
        out     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
        out     dx,ax
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        jmp     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
        out     dx,ax
        mov     ah,byte ptr colors[FOREGROUND]
        jmp     seom_xor_text_finish

seom_overwrite_text:

        xor     ah,al
        mov     al,GRAF_SET_RESET
        mov     dl,GRAF_ADDR
        out     dx,ax

seom_xor_text_finish:

        not     ah
        mov     al,GRAF_ENAB_SR
        out     dx,ax
        mov     ax,DR_XOR shl 8 + GRAF_DATA_ROT

seom_finish_up:

        out     dx,ax
        mov     ax,0FFh shl 8 + GRAF_BIT_MASK
        out     dx,ax
        push    ecx
        mov     ecx,pVRAMInstance

        ASSUME  ecx:PTR EGAMem

        pop     ecx
        ret                                       ;  for OR mode text)

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

        public prepare_for_overlap

prepare_for_overlap::

        mov     eax,clip.rcl_xRight
        mov     ecx,x                             ;x is screen lhs
        mov     ebx,rhs                           ;Zero based rhs


        add     bx,cx    ;BX = screen rhs
        movsx   EBX,BX
        jo      pfo_have_rhs            ;Use clip.rcl_xRight for right side
        smin_ax ebx

pfo_have_rhs:

        xchg    eax,ebx                           ;Need rhs in BX
        mov     eax,clip.rcl_xLeft
        smax_ax ecx
        cmp     ebx,eax
        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,eax                ; Save lhs/rhs incase we have an
        mov     wc_opaque_rhs,ebx                ;   opaquing rectangle
        or      wc_flags,WC_SET_LR               ; Set left/right into text bbox
        push    o_rect.rcl_xLeft                 ; Save real o_rect bbox
        push    o_rect.rcl_xRight
        push    o_rect.rcl_yBottom
        push    o_rect.rcl_yTop
        mov     ecx,text_bbox.rcl_yBottom
        mov     edx,text_bbox.rcl_yTop
        mov     o_rect.rcl_xLeft,eax; Set text bbox as area to opaque
        mov     o_rect.rcl_xRight,ebx
        mov     o_rect.rcl_yBottom,ecx
        mov     o_rect.rcl_yTop,edx
        mov     bl,excel
        call    output_o_rect
        pop     o_rect.rcl_yTop
        pop     o_rect.rcl_yBottom
        pop     o_rect.rcl_xRight
        pop     o_rect.rcl_xLeft

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

pfo_exit:

        ret

pfo_exit_nothing_shows:

        pop     eax
        jmp     build_restore_opaque

build_string    ENDP

        end
