;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = STRBLTC.ASM
;*
;* DESCRIPTIVE NAME = Common routines from strblt.asm
;*
;*
;* VERSION      V2.0
;*
;* DATE         09/01/88
;*
;* DESCRIPTION  This module contains common routines and declarations from   
;*              STRBLT.ASM                                                   
;*                                                                           
;* FUNCTIONS    TotallyBogusCProc
;*              translate_string,<NEA
;*              comp_extent,<NEAR,PUB
;*              get_mode_and_font,<NE
;*                               
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   03/17/87                     Walt Moore [waltm] - Created quick_clip
;*   04/09/87                     Walt Moore [waltm] - Created comp_extent.
;*   04/11/87                     Walt Moore [waltm]
;*   04/11/87                     Created comp_byte_interval
;*   04/11/87                     Created mono_bitmap_opaque
;*   04/11/87                     Created bitmap_opaque.
;*   02/23/88                     Tony Pisculli [tonyp]- Created translate_string.
;*   03/04/88                     Walt Moore [waltm] - Created get_mode_and_font
;*   08/13/88                     Walt Moore [waltm]
;*   08/13/88                     Use instance data segment to save 1K stack
;*   08/13/88                     space.
;*   09/01/88                     Written by Robert J. Carragher
;*   09/02/88                     Robert J. Carragher [t-robc]
;*   09/02/88                     Created TotallyBogusCProc
;*   08/14/90                     Viroon Touranachun [viroont]
;*   08/14/90                     Switched from Instance Data segment to
;*   08/14/90                     CompileCode segment.
;*
;*****************************************************************************/
 
        .xlist
        include cmacros.inc
INCL_GRE_CLIP           equ                      1
INCL_FONTFILEFORMAT     equ                      1
INCL_GRE_FONTS          equ                      1
        include pmgre.inc
DINCL_ROPS              equ                      1
        include driver.inc
        include strblt.inc
        include fontseg.inc
        include cmplcode.inc
        include assert.mac
        .list
        .286p
 
        ??_out  strblt
 
sBegin  PtrData
        externA INSTANCE_STACK_WORDS
sEnd
 
sBegin  Code
        assumes cs,Code

        externW MyCmplCodeData
;/*
;**       Other functions required for ExtTextOut
;*/
 
 
 
;/*
;**       These functions are found in STRBLT.ASM and are driver dependent
;*/
        externNP abc_extent
        externNP worst_case_ext
 
;/*
;**       These two tables are used to map the foreground and background
;**       mix modes onto flags to set in the accel flags variable.
;**
;**       If the foreground mix mode is leavealone then we do some tricks:
;**
;**           if the background is leavealone, then we set the ROP_IS_NOP
;**           flag in wc_flags, which lets everything happen except drawing
;**           text;
;**
;**           if the background is overpaint, then we set the foreground
;**           mode to overpaint (by virtue of not setting any flags), and
;**           set the foreground color to the background color  --  this
;**           causes invisible text.
;*/

char_fore_mix   label   byte
        db      IS_OR_TEXT                        ;CHAR_ROP_DPO
        db      0                                 ;CHAR_ROP_P
        db      0                                 ;CHAR_ROP_D -- looks like CHAR_ROP_P
        db      IS_XOR_TEXT                       ;CHAR_ROP_DPX
 
char_back_mix   label   byte
        db      0                                 ;BA_IS_XPARENT
        db      IS_OPAQUE                         ;BA_IS_OPAQUE
        db      0                                 ;this should never be used!
        db      0                                 ;this should never be used!
 
 
page
 
;/***************************************************************************
;*
;* FUNCTION NAME = TotallyBogusCProc  
;*
;* DESCRIPTION   = Creates the frame which several procs below reference.  No 
;*                 code is actually generated, just the definitions, hence the
;*                 name "Totally- BogusCProc."                                
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
        define_frame TotallyBogusCProc   ;Define frame
cBegin  <nogen>
cEnd    <nogen>
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE  quick_clip   
;*
;* DESCRIPTION   = Quick Clip Test                                                
;*                                                                                
;*                 A quick test is made to see if the given string is entirely    
;*                 clipped, possibly clipped, or completely visible.              
;*                                                                                
;*                 An entirely clipped string can be discarded immediately.  A    
;*                 completely visible string can skip the clipping code while     
;*                 the stack data is being constructed.  A possibly clipped       
;*                 string may or may not be clipped.  The clipping code must      
;*                 be run while the stack data is being constructed in this       
;*                 case.                                                          
;*                                                                                
;*                 At the same time, the string's bounding box minimum left and   
;*                 maximum right edges are computed and saved.  This will be used 
;*                 by the cursor exclusion code.                                  
;*                 
;*                 Registers Preserved:                 
;*                       None                           
;*                 Registers Destroyed:                 
;*                       AX,CX,DX,SI,DI,DS,ES,FLAGS     
;*                 
;* INPUT         =  BH = accel flags 
;*                  BL = excel flags 
;*
;* OUTPUT        = BH = new accel flags                                          
;*                 BL = excel flags                                              
;*                 text_bbox structure initialized if any text is visible        
;*                 
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
                public  quick_clip
quick_clip      proc   near
 
;/*
;**
;**                                                 ----
;**                                                     | compute how many scans are in
;**     stuff here is clipped                           | this area.  These scans are
;**                                                     | clipped out
;**                                                     |
;**      -----------------------   ----
;**     | top                                    |      | these scans fit
;**     |                                        |  ----
;**     |                                        |
;**     |   clip rectangle                       |
;**     |                                        |
;**     |                                        |
;**     | bottom                                 |
;**      -----------------------
;**
;**
;**     stuff here is clipped
;**
;**
;*/
 
        xor     dx,dx                             ;Amount clipped on top is 0
        mov     cx,y                              ;Need starting Y coordinate
        mov     di,lfd.font_height                ;  and height of the font
        mov     ax,cx                             ;Don't destroy Y coordinate
        sub     ax,clip.rcs_pts1.pts_y            ;Is Y clipped on top?
        jge     quick_clip_y_fits_on_top          ;  No, Y fits within top
 
;/*
;** The Y coordinate is less than the top of the clip rectangle. Move
;** the Y coordinate down the screen (+Y) by the amount clipped. If the
;** amount clipped is >= the font height, then the entire string is clipped
;** and can be discarded.
;*/
 
        add     di,ax                             ;Subtract clip overhang from height
        jle     quick_clip_doesnt_show            ;Nothing shows, exit now
        sub     cx,ax                             ;Offset starting Y coordinate
        neg     ax
        xchg    ax,dx
 
quick_clip_y_fits_on_top:
        mov     text_bbox.rcs_pts1.pts_y,cx       ;Save new Y coordinate
        mov     amt_clipped_on_top,dx             ;Save for output routines
 
;/*
;**
;**     The starting Y has been computed.  Compute how many scans must
;**     be clipped off the bottom of the font.   The clipping can be done
;**     by adjusting the height.
;**
;**     stuff here is clipped
;**
;**
;**      -----------------------
;**     | top                                    |
;**     |                                        |
;**     |                                        |
;**     |   clip rectangle                       |
;**     |                                        |
;**     |                                        |  ----
;**     | bottom                                 |      | these scans fit
;**      -----------------------   ----
;**                                                     | compute how many scans are in
;**                                                     | this area.  These scans are
;**     stuff here is clipped                           | clipped out
;**                                                     |
;**                                                 ----
;**
;*/
 
        mov     ax,cx                   ;Leave CX = text_bbox.rcs_pts1.pts_y
        add     ax,di                   ;Compute text_bbox.rcs_pts2.pts_y
        mov     dx,ax
        sub     ax,clip.rcs_pts2.pts_y           ;Is Y clipped on the bottom?
        jl      quick_clip_have_y_ext            ;  No, height fits within clip rect
        sub     di,ax                            ;Clip height
        jle     quick_clip_doesnt_show           ;Nothing shows, exit
        sub     dx,ax                            ;Clip bottom of text box
 
;/*
;** The string has been clipped in Y, and at least one scan will be visible.
;*/
 
quick_clip_have_y_ext:
        mov     clipped_font_height,di           ;Save height of what will be drawn
        mov     text_bbox.rcs_pts2.pts_y,dx
 
;/*
;** If the vertical portion of the text fits within the opaque rectangle,
;** then set the BOUNDED_IN_Y flag for the code which creates the stack
;** data.  When this flag is set, that code should attempt to fill to byte
;** boundaries.
;*/
 
        test    bl,OPAQUE_RECT
        jz      quick_clip_do_x
        cmp     dx,o_rect.rcs_pts2.pts_y
        jg      quick_clip_do_x                  ;Text extends below opaque bottom
        cmp     cx,o_rect.rcs_pts1.pts_y
        jl      quick_clip_do_x                  ;Text extends above opaque top
        or      bl,BOUNDED_IN_Y
 
 
;/*
;**
;**     Clip the string in X.  An attempt will be made to detect
;**     the following five cases
;**
;**              -----------------------
;**             |                                 |
;**             |                                 |
;**  case1   case2       case3                         case4   case5
;**             |                                 |
;**             |   clip rectangle               |
;**             |                                 |
;**             |                                 |
;**             |                                 |
;**              -----------------------
;**            left                                    right
;**
;**
;*/
 
;/*
;** Slip-of-hand here.  If the lhs is negative, it means that the font
;** had abc spacing and the first "a" space was negative.  We'll adjust
;** the starting X if we detect this.
;*/
 
quick_clip_do_x:
        mov     di,x
        add     di,lhs                            ;Will be 0 or negative
        mov     x,di
        mov     text_bbox.rcs_pts1.pts_x,di       ;Bounding box left hand side
        mov     cx,clip.rcs_pts2.pts_x
        cmp     di,cx
        jge     quick_clip_doesnt_show            ;Case 5
        mov     ax,rhs
        add     ax,di                             ;AX = maximum right hand side
        jo      peg_out_at_max_int
 
;/*
;** If the starting X is less than the left side of the clip rectangle,
;** then the test will be made for cases 1,2, and 4.  If the starting X
;** is within the clip rectangle, then the test will be made for cases
;** 3 or 4.
;*/
 
quick_clip_have_right_x:
        mov     dx,clip.rcs_pts1.pts_x
        cmp     di,dx
        jge     quick_clip_case_3_or_4
 
quick_clip_case_1_or_2:
        cmp     ax,dx                             ;Crossing into the left side?
        jl      quick_clip_doesnt_show            ;Case 1
        or      bl,CLIPPED_LEFT                   ;Show clipped on left side
        mov     text_bbox.rcs_pts1.pts_x,dx       ;Set new lhs for text
 
quick_clip_case_3_or_4:
        cmp     ax,cx                             ;Overhanging the right side?
        jl      quick_clip_exit                   ;  No
        or      bl,CLIPPED_RIGHT                  ;Right clipping needed
 
quick_clip_exit:
        or      bl,TEXT_VISIBLE                   ;Some part of the text may show
        mov     text_bbox.rcs_pts2.pts_x,ax       ;Save bbox right hand side
 
quick_clip_doesnt_show:
        ret
 
;*/
;** We handle the case where the string extent is unknown by setting the
;** left and right hand sides of the strings to the most negative and most
;** positive numbers and falling through the normal case code.
;*/
 
peg_out_at_max_int:
        mov     ax,MAXSHORT                       ;Make rhs as large as possible
        jmp     quick_clip_have_right_x
 
quick_clip      endp
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE   comp_byte_interval 
;*
;* DESCRIPTION   = A interval will be computed for byte boundaries.  A first  
;*                 mask and a last mask will be calculated, and possibly      
;*                 combined into the inner loop count.  If no first byte      
;*                 exists, the start address will be incremented to adjust for
;*                 it.                                                        
;*                 
;*                 Registers Preserved:         
;*                       ES,BP                  
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,SI,FLAGS   
;*
;* INPUT         = BX    = right coordinate (exclusive) 
;*                 DX    = left coordinate  (inclusive) 
;* OUTPUT        = 'C' clear                                             
;*                 DI    = offset to first byte to be altered in the scan
;*                 SI    = inner loop count                              
;*                 AL    = first byte mask (possibly 0)                  
;*                 AH    = last  byte mask (possibly 0)                  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = 'C' if interval is null 
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
        public  comp_byte_interval
comp_byte_interval proc near
 
        sub     bx,dx                             ;Compute extent of interval
        jle     return_null_interval              ;Null interval, skip it
        dec     bx                                ;Make interval inclusive
        mov     di,dx                             ;Don't destroy starting X
        shr     di,3                              ;/8 for byte address
 
;/*
;**     We now have to determine how many bits will be affected,
;**     and how they are aligned within the bytes.
;**
;**     (left_x MOD word_size) will give us the starting pixel
;**     within the left byte/word.  Adding the inclusive extent
;**     of the interval to left_x MOD word_size) and taking the
;**     result MOD word_size will give us the last pixel affected
;**     in the last byte/word.                   These pixel indexes (0:7 for bytes,
;**     0:15 for words), can be used to create the first and last
;**     altered bits mask.
;**
;**
;**     To compute the number of bytes/words in the inner loop,
;**     use the second calculation above
;**
;**             (left_x MOD word_size) + inclusive_extent
;**
;**     and divide it by the word size (8/16).   This gives you
;**     the following:
;**
;**
;**         1)  If the result is 0, then only one destination
;**             byte/word is being altered.  In this case, the
;**             start & ending masks should be ANDed together,
;**             the innerloop count set to zero, and last_mask
;**             set to to all 0's (don't alter any bits).
;**
;**                     |      x x x x x|         |
;**                     |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                      0 1 2 3 4 5 6 7
;**
;**                     start MOD 8 = 3,  extent-1 = 4
;**                     3+7 DIV 8 = 0, only altering one byte
;**
;**
;**
;**         2)  If the result is 1, then only two bytes/words
;**             will be altered.  In this case, the start and
;**             ending masks are valid, and all that needs to
;**             be done is set the innerloop count to 0.
;**
;**                     |  x x x x x x x|x x x x x x x|
;**                     |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                      0 1 2 3 4 5 6 7
;**
;**                     start MOD 8 = 1,  extent-1 = 14
;**                     3+14 DIV 8 = 1.  There is a first and last
;**                     byte but no innerloop count
;**
;**
;**
;**         3)  If the result is > 1, then some number of entire
;**             bytes/words will be altered by the innerloop.  In
;**             this case the number of innerloop bytes/words will
;**             be the result - 1.
;**
;**                     |                               x|x x x x x x x x|x
;**                     |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;**                      0 1 2 3 4 5 6 7
;**
;**                     start MOD 8 = 7,  extent-1 = 9
;**                     7+9  DIV 8 = 2.  There is a first and last
;**                     byte and an innerloop count of 1 (result - 1)
;*/
 
;/*
;**       Compute the starting bit position on the left and the ending
;**       bit position on the right
;*/
 
 
        and     dl,00000111b                      ;Compute bit index for left side
        xor     dh,dh
        add     bx,dx                             ;Compute bit index for right side
        mov     si,bx                             ;(save for inner loop count)
        and     bl,00000111b
        mov     cl,dl                             ;Compute left side altered bits mask
        mov     ax,0FFFFh
        mov     dx,ax                             ;Need this here later
        shr     al,cl                             ;AL = left side altered bytes mask
        mov     cl,bl                             ;Compute right side altered bits mask
        mov     ah,80h
        sar     ah,cl                             ;AH = right side altered bits mask
        shr     si,3                              ;Compute inner byte count
        jnz     comp_byte_dont_combine            ;loop count + 1 > 0, check it out
 
;/*
;**       Only one byte will be affected.  Combine the first and
;**       last byte masks, and set the loop count to 0.
;*/
 
        and     al,ah                             ;Will use first byte mask only
        xor     ah,ah                             ;Want last byte mask to be 0
        inc     si                                ;Fall through to set 0
 
comp_byte_dont_combine:
        dec     si                                ;Dec inner loop count (might become 0)
 
;/*
;**       If all pixels in the first byte are altered, combine the
;**       first byte into the inner loop and clear the first byte
;**       mask.  Ditto for the last byte
;*/
 
        cmp     al,dl                             ;Set 'C' if not all pixels 1
        sbb     si,dx                             ;If no 'C', sub -1 (add 1), else sub 0
        cmp     al,dl                             ;Set 'C' if not all pixels 1
        sbb     al,dl                             ;If no 'C', sub -1 (add 1), else sub 0
 
        cmp     ah,dl                             ;Set 'C' if not all pixels 1
        sbb     si,dx                             ;If no 'C', sub -1 (add 1), else sub 0
        cmp     ah,dl                             ;Set 'C' if not all pixels 1
        sbb     ah,dl                             ;If no 'C', sub -1 (add 1), else sub 0
        clc                                       ;Carry clear to show there is something
        ret
 
return_null_interval:                             ;Null interval, skip it
        stc
        ret
 
comp_byte_interval endp
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE  mono_bitmap_opaque   
;*
;* DESCRIPTION   = Fill the given bitmap with all 1's or all 0's  
;*
;*                 Registers Preserved:          
;*                       DX,SI,DS,ES,BP          
;*                 Registers Destroyed:          
;*                       AX,BX,CX,DX,DI,FLAGS    
;*
;* INPUT         = AL = first byte mask           
;*                 AH = last byte mask            
;*                 BX = height                    
;*                 DX = next scan increment       
;*                 SI = inner loop count          
;*                 ES:DI --> destination          
;*                 DS:DI --> destination          
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
        public  mono_bitmap_opaque
mono_bitmap_opaque   proc near
 
        mov     cl,byte ptr colors[BACKGROUND] ;Set 'C' to fill color
        shr     cl,1
        errn$   bitmap_opaque
 
mono_bitmap_opaque   endp
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE   bitmap_opaque 
;*
;* DESCRIPTION   =  Fill the given bitmap with all 1's or all 0's 
;*
;*                  Registers Preserved:          
;*                        DX,SI,DS,ES,BP          
;*                  Registers Destroyed:          
;*                        AX,BX,CX,DX,DI,FLAGS    
;*
;* INPUT         = AL = first byte mask          
;*                 AH = last byte mask           
;*                 BX = height                   
;*                 DX = next scan increment      
;*                 SI = inner loop count         
;*                 ES:DI --> destination         
;*                 DS:DI --> destination         
;*                 'C' set   if to fill with 1's 
;*                 'C' clear if to fill with 0's NONE
;*                 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
        public  bitmap_opaque
bitmap_opaque   proc near
 
        cld
        jnc     bitmap_opaque_0s                 ;Filling with 0's
 
;/*
;**       Filling the bitmap with all 1's.  Simply OR in the first
;**       and/or last byte masks, and STOSW 0FFFF for the inner loop.
;*/
 
        or      ax,ax                             ;If no first or last byte
        jz      bo1_inner_start                   ;  then only inner loop exists
        mov     cx,di                             ;If there is a first byte, then
        cmp     al,1                              ;  increment destination pointer
        sbb     cx,-1                             ;  for the inner loop.
        push    cx                                ;Save inner loop start addr
        mov     cx,bx                             ;Set CX = height
        or      ah,ah
        jz      bo1_first_only                    ;No last byte
        or      al,al
        jz      bo1_last_only                     ;No first byte
 
 
bo1_first_and_last:
        xchg    bx,si                             ;Set BX = delta from first to last
        inc     bx
bo1_both_loop:
        or      [di],al                           ;Do first
        or      [di][bx],ah                       ;Do last
        add     di,dx                             ;--> next scan line
        loop    bo1_both_loop
        dec     bx
        xchg    bx,si
        jmp     short bo1_restore_start_addr
 
 
bo1_last_only:
        add     di,si                             ;--> last byte of first scan
        xchg    al,ah
bo1_first_only:
        or      [di],al                           ;Do first
        add     di,dx                             ;--> next scan line
        loop    bo1_first_only
 
bo1_restore_start_addr:
        pop     di                                ;--> to first byte for inner loop
 
bo1_inner_start:
        mov     ax,0FFFFh                         ;Filling with 1's
 
;/*
;**       Inner loop for filling with both 0's and 1's, or whatever
;**       is in AX.
;*/

bo_start_inner_loop:
        or      si,si                             ;SI = inner loop count
        jz      bo_done                           ;No inner loop
        sub     dx,si                             ;BX = delta to next scan line
 
bo_inner_loop:
        mov     cx,si
        shr     cx,1
        rep     stosw
        rcl     cx,1
        rep     stosb
        add     di,dx
        dec     bx
        jnz     bo_inner_loop
        add     dx,si                             ;Restore next scan increment
 
bo_done:
        ret
 
 
;/*
;**       Filling the bitmap with all 0's.  Simply AND in the inverse
;**       of the first and/or last byte masks, and STOSW 0000 for the
;**       inner loop.
;*/
 
bitmap_opaque_0s:
        or      ax,ax                             ;If no first or last byte
        jz      bo_start_inner_loop               ;  then only inner loop exists
        mov     cx,di                             ;If there is a first byte, then
        cmp     al,1                              ;  increment destination pointer
        sbb     cx,-1                             ;  for the inner loop.
        push    cx                                ;Save inner loop start addr
        mov     cx,bx                             ;Set CX = height
        or      ah,ah
        jz      bo0_first_only                    ;No last byte
        or      al,al                             ;'C' if AL was non-zero
        jz      bo0_last_only                     ;No first byte
 
 
bo0_first_and_last:
        xchg    bx,si                             ;Set BX = delta from first to last
        inc     bx
        not     ax
bo0_both_loop:
        and     [di],al                           ;Do first
        and     [di][bx],ah                       ;Do last
        add     di,dx                             ;--> next scan line
        loop    bo0_both_loop
        dec     bx
        xchg    bx,si
        pop     di                                ;--> to first byte for inner loop
        xchg    ax,cx                             ;Set AX = 0
        jmp     short bo_start_inner_loop
 
 
bo0_last_only:
        add     di,si                             ;--> last byte of first scan
        xchg    al,ah
bo0_first_only:
        not     al
bo0_one_only_loop:
        and     [di],al
        add     di,dx                             ;--> next scan line
        loop    bo0_one_only_loop
 
bo0_restore_start_addr:
        pop     di                                ;--> to first byte for inner loop
        xchg    ax,cx                             ;Set AX = 0
        jmp     bo_start_inner_loop
 
bitmap_opaque   endp
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE  translate_string   
;*
;* DESCRIPTION   = Translate a string
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX,SI,DI,DS,ES
;*                 Registers Preserved:
;*                       BP,BX
;*
;* INPUT         = ES = SS    
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   translate_string,<NEAR,PUBLIC>,<bx>
cBegin
 
 
        mov     ax,count
        mov     cx,INSTANCE_STACK_WORDS
        mov     dx,cx
        or      ax,ax
        jns     @F
        neg     ax
        neg     cx
@@:
        cmp     ax,dx
        jle     @F
        mov     count,cx
        xchg    ax,dx
@@:
 
;/*
;** The translation loops will use the following registers:
;**
;**       AX = work
;**    ES:BX = translation vector
;**       CX = character count                      cx
;**       DX = lfd.last_char                        dx
;**    DS:SI = string pointer                       ds:si
;**       DI = lfd.first_char                       di
;**       BP = lfd.default_char                     bp
;**    SS:SP = translated string                    ss:sp
;*/

        xchg    cx,ax                             ;CX = number of characters to xlate
        std                                       ;Will walk the string backwards
        lds     si,lp_string
        assumes ds,nothing
        add     si,cx
        dec     si                                ;DS:SI --> last char of string
        mov     dx,lfd.last_char
        mov     di,lfd.first_char
        les     bx,lp_DDC
        assumes es,nothing
        add     bx,npAttrs
        push    bp
        mov     bp,lfd.default_char
        mov     ax,ss                             ;Switch to the compile code data stack
        mov     ss,MyCmplCodeData
        assumes ss,nothing
        mov     ss:proc_old_stack.sel,ax
        mov     ss:proc_old_stack.off,sp
        lea     sp,proc_initial_sp
        test    es:[bx].ca_fs,CA_MUST_MAP
        .errnz  ca_fs-ma_fs
        jz      dont_translate
 
translate:
        les     bx,es:[bx].ca_paus               ;Get mapping array
        assumes es,nothing
 
next_translate_char:
        xor     ah,ah
        lodsb
        add     ax,ax                             ;Index by words
        xchg    di,ax
        mov     di,es:[bx][di]
        xchg    ax,di
        sub     ax,di
        cmp     ax,dx
        ja      translate_char_out_of_range
translate_char_in_range:
        push    ax
        loop    next_translate_char
        jmp     short exit_translate_string
 
translate_char_out_of_range:
        mov     ax,bp
        jmp     translate_char_in_range
 
;/*
;** The default case -- we need to convert the byte index to a word
;** while we're at it, map out of range chars to the default char
;*/
 
expand_char_out_of_range:
        mov     ax,bp
        jmp     short expand_char_in_range
 
dont_translate:
next_expand_char:
        xor     ah,ah
        lodsb
        sub     ax,di
        cmp     ax,dx
        ja      expand_char_out_of_range
expand_char_in_range:
        push    ax
        loop    next_expand_char
 
;/*
;** Now clean up the stack mess we just created
;*/
 
exit_translate_string:
        mov     ax,sp                             ;Save pointer to string
        mov     dx,ss
        mov     sp,ss:proc_old_stack.off
        mov     ss,ss:proc_old_stack.sel
        assumes ss,nothing
        pop     bp                                ;Restore frame pointer
        mov     lp_string.sel,dx
        mov     lp_string.off,ax
        cld
cEnd
page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  comp_extent   
;*
;* DESCRIPTION   = Compute Extents of the String 
;*                  The extents of the string are computed and returned to the 
;*                  caller.  Mode data and font information has already been   
;*                  saved on the frame.  The string has already been mapped    
;*                  into word offset, with the first char / last char check    
;*                  being performed during the translation.                    
;*                                                                             
;*                 Registers Preserved:                                                                          
;*                       BP,BX                                                                                   
;*                 Registers Destroyed:                                                                          
;*                       AX,CX,DX,SI,DI,ES,DS,FLAGS                                                              
;*                                                                             
;* INPUT         = BH = accel flags                                                              
;*                 BL = excel flags  
;*
;* OUTPUT        = AX = rhs (right hand side), zero based
;*                 CX = lhs (left hand side).  zero based 
;*                 DI = concatenation point,  zero based  
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;*                          ------Pseudo-Code---
;*   {
;*   // The computation for fixed-pitch font extents is:
;*   //
;*   //    Y extent = height of character
;*   //    X extent = (width+CharExtra) * #chars
;*   //
;*   //    since all characters are the same width, including the default
;*   //    character, and any character extra is applied to all characters.
;*   //
;*   //
;*   // The computation for proportional font extents is:
;*   //
;*   //    Y extent = height of character
;*   //
;*   //               count-1
;*   //                ---
;*   //                \
;*   //    X extent = +   >  width(char(n))+CharExtra
;*   //                /
;*   //                ---
;*   //               n = 0
;*   //
;*   // If the width vector is present, then the above doesn't hold true.
;*   // The extents must be computed by checking each and every character,
;*   // and tracking the justification.
;*   }
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
cProc   comp_extent,<NEAR,PUBLIC>,<bx>
cBegin
        cld
        mov     cx,count
        jcxz    comp_ext_rhs_in_ax
        xchg    ax,cx
        abs_ax
        xchg    ax,cx                             ;Need count in CX
        test    bh,HAVE_WIDTH_VECT or ABC_FONT
        jnz     comp_ext_hard_way                 ;Could step backwards
        test    bh,FIXED_PITCH
        jz      comp_ext_proportional             ;Proportional font
        mov     ax,lfd.font_width                 ;Fixed pitch font
        add     ax,char_extra                     ;Always add in character extra
        imul    cx                                ;AX = string width in pixels
        jno     comp_ext_rhs_in_ax                ;Did not overflow
 
;/*
;** The string has overflowed 32K.  Return the max short int.
;*/
 
comp_ext_peg_right:
        mov     ax,MAXSHORT
        jmp     short comp_ext_rhs_in_ax
 
 
;/*
;**     Compute the extent for a string which has a width vector.
;**
;**     The actual extent code is a subroutine since it can be
;**     called by the drawing code at output time, in which case
;**     the dda locations must not be updated.
;**
;**     Currently:
;**         CX     =  character count
;*/
 
comp_ext_hard_way:
        test    bh,ABC_FONT
        jnz     comp_ext_for_abc_font
        call    worst_case_ext
        jmp     short comp_ext_have_ext
 
comp_ext_for_abc_font:
        call    abc_extent
        jmp     short comp_ext_have_ext
 
 
;/*
;**     The font is a proportional font.  Sum up the widths of all
;**     the characters.  The summation loop will use the following
;**     registers:
;**
;**         DS:SI --> string
;**         ES    --> font
;**         AX     =  word register
;**         BX     =  work register
;**         CX     =  character count
;**         DX     =  sum
;**     Currently:
;**         CX     =  character count
;**         BH     =  accel flags
;**
;** This code will never be executed for an ABC spaced font.
;*/
 
comp_ext_proportional:
        mov     ax,char_extra
        mul     cx
        jo      comp_ext_peg_right                ;Too bit already
        lds     si,lp_string
        assumes ds,nothing
        mov     es,selFont
        assumes es,FontSeg
        xchg    ax,dx                             ;Sum length into dx
 
comp_ext_prop_loop:
        lodsw
        add     ax,ax
        mov     bx,ax
        add     ax,ax
        add     bx,ax
        .errnz  (size FONT_ENTRIES) - 6
        add     dx,fsCharOffset[bx].fe_width
        jo      comp_ext_peg_right
        loop    comp_ext_prop_loop
        xchg    ax,dx                             ;Want width on AX
 
comp_ext_rhs_in_ax:
        mov     di,ax                             ;Concatenation point is extent
        xor     cx,cx                             ;lhs is always 0
        mov     lhs,cx                            ;Save these incase needed
        mov     rhs,ax
        mov     concat,di
 
comp_ext_have_ext:
        mov     dx,lfd.font_height                ;Set height
 
cEnd
page
 
;/***************************************************************************
;*
;* PUBLIC ROUTINE  get_mode_and_font 
;*
;* DESCRIPTION   = 
;*   Get Mode Parameters and Font Parameters
;*
;*   The text/background colors and any justification information
;*   is saved on the frame.  Font parameters are alos saved on the
;*   frame.
;*
;*   The following "accel" flags will be set accordingly:
;*
;*       IS_OPAQUE
;*       HAVE_WIDTH_VECT
;*       IS_XOR_TEXT
;*       IS_OR_TEXT
;*       FIXED_PITCH
;*       WIDTH_IS_8
;*
;*   The following "excel" flags will be set accordingly:
;*
;*       none (set to 0)
;*
;*   The following frame variables are initialized:
;*
;*       colors                                   Text/background colors
;*       char_extra                               # extra pixels to add each char
;*       lfd                                      local font definition structure
;*       null_char_offset                         offset of the null character
;*       selFont                                  selector of the font
;*
;*       Registers Preserved:                   
;*             CX,DX,BP                         
;*       Registers Destroyed:                   
;*             AX,SI,DI,DS,FLAGS                
;*
;* INPUT         = NONE
;*
;* OUTPUT        = BH = accel flags
;*                 BL = excel flags        
;*                 ES = SS                 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
 
        assumes ds,nothing
        assumes es,nothing
 
cProc   get_mode_and_font,<NEAR,PUBLIC>
cBegin
        lds     si,lp_DDC
        ddc?    si
        add     si,npAttrs                        ;--> ddc_ca or ddc_ma
 
        mov     bx,[si].ca_fs
        xor     ax,ax
        test    bx,CA_CHAR_EXTRA
        jz      have_extra_pel_count
        mov     ax,[si].ca_cExtraPels
have_extra_pel_count:
        mov     char_extra,ax                     ;Must save regardless of being 0
 
        and     bx,CA_FIXED_PITCH or CA_WIDTH_IS_8 or CA_ABC_SPACE or CA_CHAR_EXTRA
        .errnz  CA_FIXED_PITCH - FIXED_PITCH
        .errnz  CA_WIDTH_IS_8 - WIDTH_IS_8
        xchg    bl,bh                             ;Accel flags are in BH
        shl     bl,3                              ;Align ABC_FONT and HAVE_CHAR_EXTRA
        .errnz  CA_ABC_SPACE-0100h
        .errnz  ABC_FONT-08h
        .errnz  CA_CHAR_EXTRA-0200h
        .errnz  HAVE_CHAR_EXTRA-10h
        or      bh,bl
        xor     bl,bl                             ;Excel flags are zero

        mov     ax,word ptr [si].ca_ba.ba_bmix    ;get mix modes
        .errnz  ba_bkmix-ba_bmix-1
        xchg    al,ah                             ; 
        mov     di,ax                             ; 
        and     di,0FFh                           ;isolate back mix
        or      bh,char_back_mix[di]              ;or in back mix flags
        mov     al,ah                             ; 
        xchg    ax,di                             ; 
        and     di,0FFh                           ;isolate fore mix
        or      bh,char_fore_mix[di]              ;or in fore mix flags
 
        mov     al,[si].ca_ba.ba_ipc              ;Get text color info
        mov     ah,[si].ca_ba.ba_ipcBack          ;Get background color info
 
        cmp     di,CHAR_ROP_D                     ;fore mix LeaveAlone?
        jne     wc_flags_ok                       ;if not, don't change anything
 
        mov     al,ah                             ;set fore color same as back color
        test    bh,IS_OPAQUE
        jnz     wc_flags_ok
        or      wc_flags,ROP_IS_NOP
 
wc_flags_ok:
        mov     colors,ax
        errnz   FOREGROUND
        errnz   BACKGROUND-1
 
        mov     ax,lp_dx.off
        or      ax,lp_dx.sel
        neg     ax                                ;'C' set if width vector
        sbb     ax,ax                             ;FF if width vector, else 00
        and     al,HAVE_WIDTH_VECT
        or      bh,al
 
;/*
;** The mode data has been saved.  Now copy font data to the frame.
;*/
 
        mov     ds,[si].ca_pFont.sel              ;--> font
        assumes ds,FontSeg
        mov     selFont,ds
        lea     di,lfd                            ;Set ES:DI --> local font definition
        mov     ax,ss
        mov     es,ax
        assumes es,nothing
 
        mov     si,offset fsDef.fdCellWidth
        movsw
        .errnz  font_width
 
        movsw
        .errnz  font_height-font_width-2
        .errnz  fsDef.fdCellHeight-fsDef.fdCellWidth-2
 
;/*
;** Save the maximum width of a character.  This can be useful if a quick
;** clippping test were made to see if any clipping is required for the string.
;*/
 
        mov     si,offset fsMetrics.foca_usFirstChar
        movsw
        .errnz  first_char-font_height-2
 
        lodsw
        stosw                                     ;Save last char for null char offset
        .errnz  last_char-first_char-2            ;  calculation
        .errnz  fsMetrics.foca_usLastChar-fsMetrics.foca_usFirstChar-2
 
        movsw
        .errnz  default_char-last_char-2
        .errnz  fsMetrics.foca_usDefaultChar-fsMetrics.foca_usLastChar-2
 
;/*
;** Compute and save the offset of the null character.  The pointer to the
;** null character follows the last character.
;*/
 
        inc     ax                                ;Null character follows last character
        mov     si,dx                             ;Don't destroy DX
        mov     dx,size ABC_FONT_ENTRIES
        test    bh,ABC_FONT
        jnz     @F
        mov     dx,size FONT_ENTRIES
@@:
        mul     dx
        xchg    ax,si                             ;SI --> null character
        xchg    ax,dx                             ;Restore DX
        mov     ax,fsCharOffset[si].fe_dBits.lo
        mov     null_char_offset,ax
 
cEnd
 
page

sEnd    Code
 
        end
