;*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 = STRDRAW.ASM
;*
;* DESCRIPTIVE NAME = VGA specific code for strblt
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/17/87
;*
;* DESCRIPTION  This module contains the ega specific code for the
;*              strblt function and the ExtendedTextOut function.
;*
;* FUNCTIONS    output_o_rect
;*
;* 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                     Written by Walt Moore [waltm]
;*
;*****************************************************************************/

        .386

        .xlist

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

        include pmgre.inc
        include driver.inc
        include display.inc
        include egafam.inc
        include strblt.inc
        include extern.inc
        include protos.inc

        .list

        .MODEL FLAT

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

        .DATA

;/*
;**       Other functions required for strdraw.
;*/
        .CODE
_TUNE segment USE32 PUBLIC 'CODE'
        EXTERN  color_bitmap_opaque     :NEAR
        EXTERN  mono_bitmap_opaque      :NEAR
        EXTERN  comp_byte_interval      :NEAR


        page

;/***************************************************************************
;*
;* FUNCTION NAME = output_o_rect
;*
;* DESCRIPTION   =  Fill the opaque rectangle with the background color.
;*
;*                  Registers Preserved:
;*                        BP
;*                  Registers Destroyed:
;*                        AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* INPUT         = BL = excel flags
;*                 stack frame as per strblt
;*
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

output_o_rect 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

        DebugMsg <output_o_rect STRDRAW CLIFFL>

        test    bl,IS_DEVICE
        jz      oor_not_ega

;/*
;**       This is the EGA.  Set up for opaquing the rectangle.
;*/

        mov     dx,EGA_BASE + SEQ_DATA
        mov     al,MM_ALL
        out     dx,al
        mov     dl,GRAF_ADDR
        mov     ah,byte ptr colors[BACKGROUND]
        and     ah,MM_ALL
        mov     al,GRAF_SET_RESET
        out     dx,ax
        mov     ax,MM_ALL shl 8 + GRAF_ENAB_SR
        out     dx,ax
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        out     dx,ax
        mov     ax,0FF00h + GRAF_BIT_MASK
        out     dx,ax


oor_not_ega:

        shr     bl,2
        jnc     oor_exclusive_rects     ;No text, just output opaque rect

        errnz   TEXT_VISIBLE-00000010b

        test    accel,IS_OPAQUE         ;If in transparent mode, must always
        jz      oor_exclusive_rects     ;  opaque the rectangle

        shr     bl,1
        jc      oor_check_x_bounds      ;Skip Y range check

        errnz   BOUNDED_IN_Y-00000100b

;/*
;**       We have no idea if any of the text bounding box intersects
;**       with the opaque rectangle.  If the intersection is empty,
;**       then we can output the opaque rectangle using the same code
;**       for when there isn't any text.
;*/


oor_check_y_bounds:

        mov     eax,text_bbox.rcl_yBottom
        cmp     eax,o_rect.rcl_yTop
        jge     oor_exclusive_rects
        mov     eax,text_bbox.rcl_yTop
        cmp     eax,o_rect.rcl_yBottom
        jle     oor_exclusive_rects


;/*
;**       The rectangles overlap in Y.  Check to see if they overlap in X.
;*/

oor_check_x_bounds:

        mov     eax,text_bbox.rcl_xLeft
        cmp     eax,o_rect.rcl_xRight
        jge     oor_exclusive_rects
        mov     eax,text_bbox.rcl_xRight
        cmp     eax,o_rect.rcl_xLeft
        jnle    oor_inclusive_rects     ;Rectangles intersect somehow


;/*
;**       The rectangles are exclusive.  Just fill the opaque rectangle
;**       and exit.
;*/

oor_exclusive_rects:

        mov     ebx,o_rect.rcl_xRight
        mov     edx,o_rect.rcl_xLeft
        call    comp_byte_interval
        xchg    eax,ecx                   ;Save first/last mask
        mov     eax,o_rect.rcl_yBottom           ;Compute height of box and leave
        mov     ebx,o_rect.rcl_yTop        ;  it in BX for the opaquing
        sub     ebx,eax                   ;  subroutines
        mul     next_scan               ;Add in Y component
        add     edi,eax
        add     edi,lp_surface          ;Add any original offset into surface
        xchg    eax,ecx                   ;First/last masks need to be in AX
        mov     edx,next_scan            ;Need increment to next scan line
        jmp     opaque_routine

oor_an_exit:

        ret


;/*
;**
;**       The rectangles overlap in some unknown manner.  Compute
;**       all the areas which need to be opaqued, and opaque them
;**       (easier said than done).
;**
;**
;**       First the area completely above and below the text bounding
;**       box will be opaqued.  The scanline information will be the
;**       same for both areas (same first/last masks and inner loop
;**       counts).  Remember that any of the areas could be null.
;**
;**
;**       heights
;**
;**               ------------------------------------  o_rect.rcs_pts1.pts_y
;**              |                                    |
;**        top   |          opaque rectangle          |
;**              |                                    |
;**              |     --------------------------     | text_bbox.rcs_pts1.pts_y
;**              |    |                          |    |
;**       middle |    |    text bounding box     |    |
;**              |    |                          |    |
;**              |     --------------------------     | text_bbox.rcs_pts2.pts_y
;**       bottom |                                    |
;**              |                                    |
;**               ------------------------------------  o_rect.rcs_pts2.pts_y
;**
;**
;**       For the top rectangle:
;**
;**               starting Y is o_rect.rcs_pts1.pts_y
;**               height is MAX(text_bbox.rcs_pts1.pts_y-o_rect.rcs_pts1.pts_y,0)
;**
;**       For the bottom rectangle:
;**
;**               starting Y is text_bbox.rcs_pts1.pts_y
;**               height is MAX(o_rect.rcs_pts2.pts_y-text_bbox.rcs_pts2.pts_y,0)
;**
;**       For the middle rectangle:
;**
;**               starting Y is o_rect.rcs_pts1.pts_y + height of top
;**               height is MAX(text_bbox.rcs_pts2.pts_y-starting Y,0)
;**
;*/


oor_inclusive_rects:

        mov     edx,text_bbox.rcl_yBottom        ;Compute opaque rect area above the
        mov     eax,o_rect.rcl_yBottom           ;  text bounding box
        sub     dx,ax
        sbb     ecx,ecx
        not     ecx
        and     ecx,edx                   ;CX = height of top, or 0
        jz      oor_comp_bottom
        mul     next_scan
        xchg    ebx,eax                   ;Set BX = offset to start of top scan

oor_comp_bottom:

        mov     eax,text_bbox.rcl_yTop     ;Compute opaque rect area below the
        mov     edx,o_rect.rcl_yTop        ;  text bounding box
        sub     dx,ax
        sbb     esi,esi
        not     esi
        and     esi,edx                   ;SI = height of bottom, or 0
        jz      oor_comp_middle_y
        mul     next_scan               ;AX = offset to start of top scan

oor_comp_middle_y:

        mov     edi,o_rect.rcl_yBottom           ;Add o_rect.rcl_yBottom and height of top
        add     edi,ecx                   ;  area to get middle Y

oor_see_if_top_or_bottom:

        mov     edx,esi                   ;If both heights are 0, then
        or      edx,ecx                   ;  no top and no bottom
        jz      oor_see_about_middle

;/*
;**       There is at least a top or a bottom.  Compute the scan interval
;**       and fill the areas.
;*/

        push    edi                      ;Save middle area Y
        push    eax                      ;Save bottom area Y offset
        push    esi                      ;Save bottom area height
        push    ebx                      ;Save top    area Y offset
        push    ecx                      ;Save top    area height
        mov     ebx,o_rect.rcl_xRight
        mov     edx,o_rect.rcl_xLeft
        call    comp_byte_interval
        mov     edx,next_scan            ;Set next scan increment incase bitmap
        add     edi,lp_surface          ;Add any initial offset to bits/device
        pop     ebx                      ;Get top area height
        pop     ecx                      ;Get top area Y offset
        or      ebx,ebx
        jz      oor_see_about_bottom    ;There is no top area
        push    edi                      ;Save X component of start address
        push    eax                      ;Save first/last mask
        add     edi,ecx                   ;--> first byte
        call    opaque_routine
        pop     eax                      ;Restore first/last mask
        pop     edi                      ;Restore X component of start address

oor_see_about_bottom:

        pop     ebx                      ;Get bottom area height
        pop     ecx                      ;Get bottom area Y offset
        or      ebx,ebx
        jz      oor_no_bottom_area      ;There is no bottom area
        add     edi,ecx                   ;--> first byte
        call    opaque_routine

oor_no_bottom_area:

        pop     edi                      ;Restore middle Y coordinate


;/*
;**       missing_code    <x picture goes here>
;*/

oor_see_about_middle:

        mov     eax,o_rect.rcl_yTop        ;Bottom of middle bytes is
        mov     ebx,text_bbox.rcl_yTop     ;  minimum of these two
        smin_ax ebx
        sub     eax,edi                    ;Compute height of middle area
        jle     oor_a_return               ;This should never occur, but....
        mov     opaque_height,eax
        mov     eax,next_scan              ;Compute Y offset of middle start
        mul     edi
        add     eax,lp_surface
        mov     temp_off_lp_bits,eax

        mov     edx,text_bbox.rcl_xRight      ;Compute rhs interval
        mov     ebx,o_rect.rcl_xRight
        call    comp_byte_interval
        mov     ebx,text_bbox.rcl_xLeft       ;For lhs interval computation
        mov     edx,o_rect.rcl_xLeft
        jc      oor_check_lhs_only       ;No rhs
        push    esi                      ;Save inner loop count
        push    edi                      ;Save X offset into scan
        push    eax                      ;Save first/last mask
        call    comp_byte_interval
        jnc     oor_output_both_sides    ;There was a left and a right

;/*
;**       There was only a rhs.  Restore the saved interval parameters
;**       and output the rectangle.
;*/

oor_process_rhs:

        pop     eax                      ;Restore first/last mask
        pop     edi                      ;Restore X offset
        pop     esi                      ;Restore inner loop count

oor_output_one_rect:

        add     edi,temp_off_lp_bits     ;--> first byte
        mov     ebx,opaque_height        ;Set height
        mov     edx,next_scan            ;Set index to next scanline
        jmp     opaque_routine          ;Invoke opaquing routine and exit


;/*
;**       There was only a lhs.  Compute the interval parameters
;**       and see if the text string was bounded in Y.  If it was,
;**       then any portion of the last byte of the lhs interval
;**       will have been handled by the string output code.
;*/

oor_check_lhs_only:

        call    comp_byte_interval      ;Compute lhs interval
        jc      oor_a_return            ;No interval exists, exit
        jmp     oor_output_one_rect

oor_a_return:

        ret

;/*
;**       The parameters for the lhs and rhs have been computed.
;**       If the lhs stops in the same byte that the rhs starts,
;**       then we'll want to combine the lhs last byte mask with
;**       the rhs first byte mask.
;*/

oor_output_both_sides:

        mov     ecx,text_bbox.rcl_xLeft       ;Compute the byte address of the
        and     cl,11111000b            ;  start and end of the text string
        mov     edx,text_bbox.rcl_xRight
        and     dl,11111000b
        cmp     edx,ecx
        jne     oor_output_both_anyway  ;Ends/starts in different bytes

;/*
;**       We have to combine the last byte mask of the lhs with the
;**       first byte mask of the rhs.  If one of the intervals consists
;**       only of the mask, we want to make it disappear.  Both the last
;**       byte mask for the lhs and the first byte mask for the rhs must
;**       exist.
;*/

oor_overlapping_middle:

        pop     ebx                      ;Restore rhs first/last mask
        pop     edx                      ;Restore rhs X offset
        pop     ecx                      ;Restore rhs inner loop count

        or      esi,esi                   ;If an inner loop for lhs, combine
        jnz     oor_combine_with_lhs    ;  rhs first mask with lhs last mask
        or      ah,ah                   ;If a last byte mask for lhs, combine
        jnz     oor_combine_with_lhs    ;  rhs first byte mask with it

;/*
;**       There is only a first byte on the lhs.  Combine it with the
;**       rhs byte.  This will eliminate the entire lhs.  We don't
;**       have to worry about there not being a rhs first byte mask
;**       (and therefore decrementing the destination pointer) since
;**       there must be one for the bytes to overlap.
;*/

        or      eax,ebx                   ;Combine lhs mask with rhs masks
        mov     esi,ecx                   ;Set inner loop count
        mov     edi,edx
        jmp     oor_output_one_rect

oor_combine_with_lhs:

        or      ah,bl                   ;Combine the masks
        xor     bl,bl                   ;Clear old mask
        inc     edx                      ;Increment rhs start offset
        push    ecx                      ;Save inner loop count
        push    edx                      ;Save X offset into scan
        push    ebx                      ;Save first/last mask

oor_output_both_anyway:

        call    oor_output_one_rect     ;Do whatever for lhs
        jmp     oor_process_rhs         ;Do whatever for rhs

        page


;/***************************************************************************
;*
;* PUBLIC ROUTINE  reset_ega
;*
;* DESCRIPTION   = Reset the card
;*
;*                 Registers Preserved:
;*                       None
;*                 Registers Destroyed:
;*                       AL,DX
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

                public  reset_ega

reset_ega::

        DebugMsg <reset_ega STRDRAW CLIFFL>

        mov     al,MM_ALL               ;Enable all planes
        mov     dx,EGA_BASE+SEQ_DATA
        out     dx,al
        mov     ax,GRAF_ENAB_SR         ;Disable set/reset
        mov     dl,GRAF_ADDR
        out     dx,ax
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        out     dx,ax
        mov     ax,0FF00h+GRAF_BIT_MASK ;Enable all bits
        out     dx,ax
        ret

        page


;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_opaque
;*
;* DESCRIPTION   = Fill the given bitmap with the background color
;*
;*                 Registers Preserved:
;*                       SI,DS,ES,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,DI,FLAGS
;*
;* INPUT         = AL = first byte mask
;*                 AH = last byte mask
;*                 BX = height
;*                 SI = inner loop count
;*                 ES:DI --> destination
;*                 DS:DI --> destination
;*
;*                 EGA programmed for:
;*                         Set/Reset enabled
;*                         Set/Reset = background color
;*                         M_PROC_WRITE, M_DATA_READ
;*                         DR_SET
;*                         All planes enabled
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

                public ega_opaque

ega_opaque::

        cld
        or      eax,eax                 ;If no first or last byte
        jz      eo_start_inner_loop     ;  then only inner loop exists
        mov     ecx,edi                 ;If there is a first byte, then
        cmp     al,1                    ;  increment destination pointer
        sbb     ecx,-1                  ;  for the inner loop.
        push    ecx                     ;Save inner loop start addr
        xchg    ah,al                   ;Need mask in AH
        or      ah,ah                   ;Does first partial byte exist?
        jz      eo_not_this_byte        ;Byte doesn't exist

eo_next_partial:

        mov     ecx,eax                   ;Save last byte mask
        mov     dx,EGA_BASE+GRAF_ADDR
        mov     al,GRAF_BIT_MASK
        out     dx,ax
        xchg    eax,ecx                   ;Restore last byte mask
        mov     edx,edi                   ;Save starting address for right side
        mov     ecx,ebx                   ;Set height

eo_partial_loop:

        xchg    BYTE PTR [edi],ah
        add     edi,SCREEN_CBSCAN
        dec     ecx
        jnz     eo_partial_loop

;/*
;**       If there was a left side partial byte, then to get to the
;**       right side partial byte, we need to add InnerLoopCount+1.
;**       to the original offset.  If there wasn't a left side byte,
;**       we only want to add InnerLoopCount.
;**
;**       So, we increment the address by one assuming that we just
;**       came through the loop for the first byte.  If this is the
;**       second time through the loop, it doesn't matter that we
;**       incremented the address.
;*/

        mov     edi,edx                   ;Restore first byte address
        inc     edi                      ;Incase this was first byte

eo_not_this_byte:

        add     edi,esi                   ;--> last byte
        and     eax,00FFh                ;Zero this byte's mask
        xchg    ah,al                   ;Need mask in AH
        jnz     eo_next_partial         ;Looks like a partial last byte
        pop     edi                      ;Restore inner loop start address

eo_start_inner_loop:

        or      esi,esi                   ;SI = inner loop count
        jz      eo_done                 ;No inner loop
        mov     dx,EGA_BASE+GRAF_ADDR   ;Enable all bits for alteration
        mov     ax,0FF00h + GRAF_BIT_MASK
        out     dx,ax
        mov     edx,SCREEN_CBSCAN        ;Compute index to next scan
        sub     edx,esi
        inc     ebx
        shr     ebx,1
        jnc     eo_inner_loop_2

eo_inner_loop:
        mov     ecx,esi
        rep     stosb
        add     edi,edx

eo_inner_loop_2:
        mov     ecx,esi
        rep     stosb
        add     edi,edx
        dec     ebx
        jnz     eo_inner_loop

eo_done:
        ret

        page


;/***************************************************************************
;*
;* PUBLIC ROUTINE  get_device_data
;*
;* DESCRIPTION   = All device specific local variables are intiialized.
;*
;*                 This function must be called after both get_clip and
;*                 quick_clip (when the character count is positive) have been
;*                 called.  This requirement is because of the manner in which
;*                 huge bitmaps are handled), and for cursor exclusion.
;*
;*                 Registers Preserved:
;*                       BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

v_gdd_dev_is_bitmap:

        jmp     gdd_dev_is_bitmap

gdd_device_isnt_enabled:

        stc
        jmp     gdd_exit

                public get_device_data

get_device_data::

        DebugMsg <get_device_data STRDRAW CLIFFL>

        mov     esi,lp_DDC

        ASSUME  esi:PTR DDC

        mov     esi,[esi].ddc_npsd

        ASSUME  esi:PTR SURFACE

        test    [esi].sd_fb,SD_DEVICE
        jz      v_gdd_dev_is_bitmap
        or      excel,IS_DEVICE

        mov     eax,[esi].sd_pBits
        mov     lp_surface,eax

;/*
;**       This is the display.  Exclude the cursor from the union of
;**       the opaque rectangle and the estimated text bounding box.
;**
;**       Because of the approximation technique used for the text
;**       bounding box, text X coordinates must be clipped to the
;**       EGA's physical dimensions.
;**
;**       Exclusion code expects:
;**               (cx) = left
;**               (dx) = top
;**               (si) = right  (inclusive)
;**               (di) = bottom (inclusive)
;*/


        mov     bl,excel
        test    bl,TEXT_VISIBLE             ;If no visible text, then opaque
        jz      gdd_exclude_is_opaque       ;  rect is the exclusion area
        test    bl,OPAQUE_RECT              ;If no opaque rectangle
        jz      gdd_exclude_text_or_both    ;  clip to text bbox
        test    eto_options,ETO_OPAQUE_CLIP ;If text isn't clipped to opaque
        jz      gdd_exclude_text_or_both    ;  rect, clip to the union

gdd_exclude_is_opaque:

        mov     ecx,o_rect.rcl_xLeft
        mov     edx,o_rect.rcl_yBottom
        mov     esi,o_rect.rcl_xRight
        mov     edi,o_rect.rcl_yTop
        jmp     gdd_exclude_have_rect

gdd_exclude_text_or_both:

        mov     eax,text_bbox.rcl_xLeft       ;Clip text left to screen left
        cwd                             ;DX = FFFF if < 0
        not     dx                      ;DX = 0000 if < 0, FFFF if greater
        and     ax,dx                   ;AX = min(AX,0)
        xchg    ecx,eax
        mov     eax,text_bbox.rcl_xRight      ;Clip text right to screen right

        smin_ax  SCREEN_CX

        xchg    eax,esi                   ;SI is now rhs
        mov     edx,text_bbox.rcl_yBottom
        mov     edi,text_bbox.rcl_yTop
        test    bl,OPAQUE_RECT
        jz      gdd_exclude_have_rect

;/*
;**       We have to exclude the union of the opaque rectangle and
;**       the text bounding box.
;*/

        mov     ebx,edx                   ;BX = text_bbox.rcl_yBottom
        mov     eax,o_rect.rcl_yBottom

        smin_ax ebx

        xchg    ebx,eax
        mov     eax,o_rect.rcl_xLeft

        smin_ax ecx

        xchg    eax,ecx
        mov     eax,o_rect.rcl_xRight

        smax_ax esi

        xchg    esi,eax
        mov     eax,o_rect.rcl_yTop

        smax_ax edi

        xchg    eax,edi
        mov     edx,ebx

gdd_exclude_have_rect:

        dec     esi                      ;Want rhs and bottom to be inclusive
        dec     edi
        call    far_exclude

;/*
;**       The exclusion has been taken care of.  Now initialize
;**       the frame variables for the EGA.  If there is an opaquing
;**       rectangle to be output, then initialize the EGA for doing
;**       it.
;*/

        mov     eax,SCREEN_CBSCAN        ;Compute adjustment from bottom
        mov     next_scan,eax            ;  of character to top of
        mul     clipped_font_height     ;  next character
        dec     eax
        mov     cell_adjust,eax
        mov     opaque_routine,OFFSET ega_opaque

        mov     ebx,colors
        and     ebx,MM_ALL shl 8 + MM_ALL
        mov     colors,ebx
;/*
;**       Initialize Tony's Bar -n- Grill to the background color.
;*/

        mov     dx,EGA_BASE + GRAF_ADDR
        INVOKE  InitTonysBarNGrill
        mov     ecx,1
        clc

        ret


;/*
;**       This is a memory bitmap.  Initialize the frame variables for
;**       either a color or a monochrome bitmap.
;**
;*/

gdd_dev_is_bitmap:

gdd_small_bitmap:

        mov     eax,[esi].sd_pBits
        mov     lp_surface,eax

gdd_finish_bitmap:                      ;Huge bitmap code can jump here

        mov     eax,[esi].sd_pBits
        mov     lp_surface,eax
        mov     eax,[esi].sd_cbScan
        mov     next_plane,eax
        mov     eax,[esi].sd_dScan
        mov     next_scan,eax
        mul     clipped_font_height     ;Compute adjustment from bottom
        dec     eax                      ;  of character to top of
        mov     cell_adjust,eax          ;  next character

        mov     edx,OFFSET color_bitmap_opaque
        mov     ecx,BITS_PEL

        .errnz  high BITS_PEL

        mov     eax,colors
        test    [esi].sd_fb,SD_COLOR
        jnz     gdd_is_color_bitmap
        mov     cl,1                    ;1 plane
        mov     edx,OFFSET mono_bitmap_opaque
        shr     eax,4                    ;Bitmap routines expect the mono bit

        errnz   MONO_BIT-00010000b      ;  in D0

        mov     colors,eax

gdd_is_color_bitmap:

        mov     opaque_routine,edx
        mov     num_planes,cl


;/*
;**
;**       Create a more useful form of the background/foreground color:
;**
;**       XOR the two colors together.  This will give a 1 wherever
;**       the colors are different.  This 1 (sign extended) will be
;**       used as an AND mask with the character pattern.  The result
;**       of this will be XORed with the background color to give the
;**       destination byte.
;**
;*/

        mov     dl,accel                
        test    dl,IS_XOR_TEXT          
        jnz     gdd_cbm_get_color       
        test    dl,IS_OR_TEXT
        jnz     gdd_cbm_set_or

gdd_cbm_xor_color:

        xor     al,ah

        mov     dl,cl                   ; save number of planes

gdd_cbm_get_color:

        shr     al,1
        rcr     bl,1
        shr     ah,1
        rcr     bl,1
        loop    gdd_cbm_get_color
        shr     dl,1                    ; Is number of planes odd (i.e. 1)?
        jnc     gdd_cbm_store_special_color
        shr     bl,6                    ; move colors to low bits if mono

gdd_cbm_store_special_color:

        mov     special_bm_opaque_color,bl
        mov     ecx,1
        clc
        ret

gdd_cbm_set_or:

        or      al,ah                   ;OR background into foreground
        jmp     gdd_cbm_xor_color


gdd_exit:

        ret

output_o_rect   ENDP
_TUNE ENDS
        end
