;*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 = STRDRAW.ASM
;*
;* DESCRIPTIVE NAME = 8514 specific code for strblt
;*
;*
;* VERSION      V2.0
;*
;* DATE         03/17/87
;*
;* DESCRIPTION  This module contains the 8514 specific code for the
;*              strblt function and the ExtendedTextOut function.     
;*                                                                    
;* FUNCTIONS    output_o_rect
;*              opaque_8514
;*              get_device_data
;*
;* 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]  
;*   08/18/87                     Walt Moore [waltm] Added test of the disabled
;*                                flag.
;*   09/24/88                     Mitchell McLain [gssc!mmm] Fixed fetch of
;*                                MONO_BIT to be from either ddc_ca or ddc_ma.
;*   09/28/88                     Bob Grudem [bobgru] Fixed the way
;*                                special_bm_opaque_color was handled for mono
;*                                bitmaps.
;*   08/27/90                     rajivg Removed the old font caching code.
;*****************************************************************************/


        .xlist
        include cmacros.inc
INCL_GRE_CLIP           equ     1
INCL_FONTFILEFORMAT     equ     1
        include pmgre.inc
        include driver.inc
        include display.inc
        include 8514.inc
        include 8514mem.inc
        include strblt8.inc
        include fontseg.inc
        .list

        ??_out  strdraw

        externFP InternalExtTextOut
        externFP far_exclude                          ;Exclude area from screen
        externFP cache_font

sBegin  PtrData
        externB screen_busy             ; screen busy semaphore
sEnd    PtrData

sBegin  Code
        assumes cs,Code

        externW MyPtrCodeData           ; for access to pointer data segment

page

;/*
;**       Link time constants describing the size and color format
;**       that the 8514 will be running in.
;*/

        externA SCREEN_CX               ;Screen width in pixels
        externA SCREEN_CY               ;Screen height in pixels


;/*
;**       Other functions required for strdraw.
;*/

        externNP color_bitmap_opaque
        externNP mono_bitmap_opaque
        externNP comp_byte_interval
        externNP global_alloc
        externNP global_free

sEnd    Code


sBegin  Code
        assumes cs,Code
        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
;*
;**************************************************************************/


;/*
;** Remember, when checking the rectangles for intersection that their corners
;** are arranged thusly:
;**
;**   +---------------------------------------------------------------+
;**   | (0,0) of screen                                               |
;**   |                                                               |
;**   |       blah_blah.rcs_pts1                                      |
;**   |       +------------------------------+                        |
;**   |       |                              |                        |
;**   |       |                              |                        |
;**   |       |                              |                        |
;**   |       +------------------------------+                        |
;**   |                                      blah_blah.rcs_pts2       |
;**   |                                                               |
;**   |                                                               |
;**   |                                         (XMAX,YMAX) of screen |
;**   +---------------------------------------------------------------+

        assumes ds,nothing
        assumes es,nothing

define_frame output_o_rect              ;Define strblt's frame

cBegin  <nogen>
cEnd    <nogen>

real_output_o_rect      proc    near

        test    bl,IS_DEVICE            ; Going to 8514?
        jnz     oor_8514                ; Yes.

        mov     ax,seg_lp_surface       ;DS and ES will always point to the
        mov     ds,ax                   ;  segment of the destination
        assumes ds,nothing              ;  surface while in this routine,
        mov     es,ax                   ;  if the surface is a bitmap.
        assumes es,nothing

        jmp     short oor_not_8514

oor_8514:

;/*
;** Going to the 8514.  Set the hardware clip rectangle to full screen,
;** so opaquing works.  Enable all planes for output.
;*/

        WaitQ   5                       ; Wait for room on 8514 input queue
        outwQ   XMIN,(0+XMIN_2DECODE)   ; Top of screen
        .errnz  XMIN_2DECODE and 0000111111111111b

        outwQ   YMIN,(0+YMIN_2DECODE)   ; Left of screen
        .errnz  YMIN_2DECODE and 0000111111111111b

        mov     ax,SCREEN_CX            ; Width of screen
        dec     ax                      ; Right of screen
        or      ax,XMAX_2DECODE         ; Add in secondary decode bits
        .errnz  XMAX_2DECODE and 0000111111111111b
        outwQ   XMAX                    ; Inform 8514 of right X of clip rect.

        mov     ax,SCREEN_CY            ; Height of screen
        dec     ax                      ; Bottom of screen
        or      ax,YMAX_2DECODE         ; Add in secondary decode bits
        .errnz  YMAX_2DECODE and 0000111111111111b
        outwQ   YMAX                    ; Inform 8514 of bottom Y of clip rect.

        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES; Enable all planes for writing


oor_not_8514:
        test    bl,TEXT_VISIBLE
        jz      oor_exclusive_rects     ;No text, just output opaque rect

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

        test    bl,BOUNDED_IN_Y
        jnz     oor_check_x_bounds      ;Skip Y range check


;/*
;**       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     ax,text_bbox.rcs_pts1.pts_y
        cmp     ax,o_rect.rcs_pts2.pts_y
        jge     oor_exclusive_rects
        mov     ax,text_bbox.rcs_pts2.pts_y
        cmp     ax,o_rect.rcs_pts1.pts_y
        jle     oor_exclusive_rects


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

oor_check_x_bounds:
        mov     ax,text_bbox.rcs_pts1.pts_x
        cmp     ax,o_rect.rcs_pts2.pts_x
        jge     oor_exclusive_rects
        mov     ax,text_bbox.rcs_pts2.pts_x
        cmp     ax,o_rect.rcs_pts1.pts_x
        jnle    oor_inclusive_rects     ;Rectangles intersect somehow

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

oor_exclusive_rects:
        test    bl,IS_DEVICE            ; Going to the device?
        jz      oor_exclusive_rects_to_bitmap

;/*
;** Special case code for going to the device.
;*/

        mov     bx,o_rect.rcs_pts1.pts_x; Start X of rectangle
        mov     cx,o_rect.rcs_pts1.pts_y; Start Y of rectangle
        mov     si,o_rect.rcs_pts2.pts_x; Right X of rectangle
        sub     si,bx                   ; Width of rectangle
        mov     di,o_rect.rcs_pts2.pts_y; Lower Y of rectangle
        sub     di,cx                   ; Height of rectangle
        jmp     opaque_routine

;/*
;** Code for going to a bitmap
;*/

oor_exclusive_rects_to_bitmap:
        mov     bx,o_rect.rcs_pts2.pts_x
        mov     dx,o_rect.rcs_pts1.pts_x
        mov     di,dx                   ; DI = left edge of rectangle
        mov     si,bx                   ; SI = right edge of rectangle
        sub     si,dx                   ; SI = width of rectangle
        cmp     num_planes,0ffh         ; Going to a color bitmap?
        je      @F                      ; Yes.
        call    comp_byte_interval
        xchg    ax,cx                   ;Save first/last mask
@@:     mov     ax,o_rect.rcs_pts1.pts_y;Compute height of box and leave
        mov     bx,o_rect.rcs_pts2.pts_y;  it in BX for the opaquing
        sub     bx,ax                   ;  subroutines
        mul     next_scan               ;Add in Y component
        add     di,ax
        add     di,off_lp_surface       ;Add any original offset into surface
        xchg    ax,cx                   ;First/last masks need to be in AX
        mov     dx,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     dx,text_bbox.rcs_pts1.pts_y ;Compute opaque rect area above the
        mov     ax,o_rect.rcs_pts1.pts_y    ;  text bounding box
        sub     dx,ax
        sbb     cx,cx
        not     cx
        and     cx,dx                   ;CX = height of top, or 0
        jz      oor_comp_bottom
        mul     next_scan
        xchg    bx,ax                   ;Set BX = offset to start of top scan

oor_comp_bottom:
        mov     ax,text_bbox.rcs_pts2.pts_y ;Compute opaque rect area below the
        mov     dx,o_rect.rcs_pts2.pts_y    ;  text bounding box
        sub     dx,ax
        sbb     si,si
        not     si
        and     si,dx                   ;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     di,o_rect.rcs_pts1.pts_y;Add o_rect.rcs_pts1.pts_y and height of top
        add     di,cx                   ;  area to get middle Y

oor_see_if_top_or_bottom:
        mov     dx,si                   ;If both heights are 0, then
        or      dx,cx                   ;  no top and no bottom
        jz      oor_see_about_middle


;/*
;**       There is at least a top or a bottom.
;*/

        push    di                      ;Save middle area Y
        push    ax                      ;Save bottom area Y offset
        push    si                      ;Save bottom area height
        push    bx                      ;Save top    area Y offset
        push    cx                      ;Save top    area height
        test    excel,IS_DEVICE         ; Going to screen?
        jz      oor_top_to_bitmap       ; Handle bitmaps if not

;/*
;** Set up for call to special-case screen code.
;*/

        mov     bx,o_rect.rcs_pts1.pts_x; Start X of both top and bottom
        mov     si,o_rect.rcs_pts2.pts_x; Right X of both top and bottom
        sub     si,bx                   ; Width of both top and bottom
        pop     di                      ; Height of top area
        add     sp,2                    ; Don't care about top area Y offset
        or      di,di
        jz      oor_screen_see_about_bottom

        mov     cx,o_rect.rcs_pts1.pts_y; Start Y of rectangle
        call    opaque_routine

oor_screen_see_about_bottom:
        mov     cx,text_bbox.rcs_pts2.pts_y; Start Y
        pop     di                      ; Height of bottom area
        add     sp,2                    ; Don't care about bottom area Y offset
        or      di,di
        jz      oor_no_bottom_area

        call    opaque_routine
        jmp     short oor_no_bottom_area

oor_top_to_bitmap:
        mov     bx,o_rect.rcs_pts2.pts_x
        mov     dx,o_rect.rcs_pts1.pts_x
        mov     di,dx                   ; DI = left edge of rectangle
        mov     si,bx                   ; SI = right edge of rectangle
        sub     si,dx                   ; SI = width of rectangle
        cmp     num_planes,0ffh         ; Going to a color bitmap?
        je      @F                      ; Yes.
        call    comp_byte_interval
@@:     mov     dx,next_scan            ;Set next scan increment incase bitmap
        add     di,off_lp_surface       ;Add any initial offset to bits/device
        pop     bx                      ;Get top area height
        pop     cx                      ;Get top area Y offset
        or      bx,bx
        jz      oor_see_about_bottom    ;There is no top area
        push    di                      ;Save X component of start address
        push    ax                      ;Save first/last mask
        add     di,cx                   ;--> first byte
        call    opaque_routine
        pop     ax                      ;Restore first/last mask
        pop     di                      ;Restore X component of start address

oor_see_about_bottom:
        pop     bx                      ;Get bottom area height
        pop     cx                      ;Get bottom area Y offset
        or      bx,bx
        jz      oor_no_bottom_area      ;There is no bottom area
        add     di,cx                   ;--> first byte
        call    opaque_routine

oor_no_bottom_area:
        pop     di                      ;Restore middle top Y coordinate


        missing_code    <x picture goes here>

oor_see_about_middle:
        mov     ax,o_rect.rcs_pts2.pts_y        ;Bottom of middle bytes is
        mov     bx,text_bbox.rcs_pts2.pts_y     ;  minimum of these two
        smin_ax bx
        sub     ax,di                   ;Compute height of middle area
        jg      @F
        jmp     oor_a_return            ;This should never occur, but....
@@:     mov     opaque_height,ax
        test    excel,IS_DEVICE         ; Going to the screen?
        jz      oor_see_about_middle_to_bitmap; No


;/*
;** The 8514 requires a lot less fussing around than going to a bitmap does.
;** Figure out the lhs and rhs rectangles, if they exist, and draw them.
;*/

        mov     cx,di                   ; Top Y of both lhs and rhs
        mov     di,ax                   ; Height for both lhs and rhs
        mov     si,text_bbox.rcs_pts1.pts_x ; Width of lhs is distance between
        mov     bx,o_rect.rcs_pts1.pts_x    ;  these two coordinates.
        sub     si,bx                   ; Width of lhs
        jbe     oor_rhs_to_screen       ; Zero or below means no lhs

        call    opaque_routine          ; Draw lhs

oor_rhs_to_screen:
        mov     si,o_rect.rcs_pts2.pts_x   ; Width of rhs is distance between
        mov     bx,text_bbox.rcs_pts2.pts_x;   these two coordinates
        sub     si,bx
        jbe     oor_a_return            ; Zero or below means no rhs

        jmp     opaque_routine          ; Draw rhs



;/*
;** Do the fussing around required to draw the rhs and lhs rectangles to
;** a bitmap.
;*/

oor_see_about_middle_to_bitmap:
        mov     ax,next_scan            ;Compute Y offset of middle start
        mul     di
        add     ax,off_lp_surface
        mov     temp_off_lp_bits,ax

        mov     dx,text_bbox.rcs_pts2.pts_x      ;Compute rhs interval
        mov     bx,o_rect.rcs_pts2.pts_x
        cmp     num_planes,0ffh         ; Going to a color bitmap?
        jne     @F                      ; No
        mov     di,dx                   ; DI = left edge of rectangle
        mov     si,bx                   ; SI = right edge of rectangle
        sub     si,dx                   ; SI = width of rectangle
        mov     bx,text_bbox.rcs_pts1.pts_x ; For lhs interval computation
        mov     dx,o_rect.rcs_pts1.pts_x
        jle     oor_check_lhs_only
        push    si                      ; Save inner loop count
        push    di                      ; Save X offset into scan
        push    ax                      ; Place holder
        mov     di,dx                   ; Left edge of rectangle
        mov     si,bx                   ; Right edge of rectangle
        sub     si,dx                   ; Width of rectangle
        jg      oor_output_both_sides   ; Jump if anything to do

        jmp     short oor_process_rhs

@@:     call    comp_byte_interval
        mov     bx,text_bbox.rcs_pts1.pts_x       ;For lhs interval computation
        mov     dx,o_rect.rcs_pts1.pts_x
        jc      oor_check_lhs_only      ;No rhs
        push    si                      ;Save inner loop count
        push    di                      ;Save X offset into scan
        push    ax                      ;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     ax                      ;Restore first/last mask
        pop     di                      ;Restore X offset
        pop     si                      ;Restore inner loop count

oor_output_one_rect:
        add     di,temp_off_lp_bits     ;--> first byte
        mov     bx,opaque_height        ;Set height
        mov     dx,next_scan            ;Set index to next scanline
        jmp     opaque_routine          ;Invoke opaquing routine and exit

;/*
;**       There was only a lhs.
;*/

oor_check_lhs_only:
        cmp     num_planes,0ffh         ; Going to a color bitmap?
        jne     @F                      ; No
        mov     di,dx                   ; Left edge of rectangle
        mov     si,bx                   ; Right edge of rectangle
        sub     si,dx                   ; Width of rectangle
        jle     oor_a_return            ; No interval, return
        jmp     oor_output_one_rect

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

oor_a_return:
        ret

;/*
;** There is both an lhs and an rhs rectangle.  Output both by referring to
;** labels above for the individual rectangles.
;*/

oor_output_both_sides:
        pop     ax                      ;Restore first/last mask
        pop     di                      ;Restore X offset
        pop     si                      ;Restore inner loop count
        call    oor_output_one_rect
        mov     bx,text_bbox.rcs_pts1.pts_x
        mov     dx,o_rect.rcs_pts1.pts_x
        jmp     oor_check_lhs_only

real_output_o_rect      endp
        page

;/***************************************************************************
;*
;* PUBLIC ROUTINE  ega_opaque  
;*
;* DESCRIPTION   = Fill the given bitmap with the background color 
;*
;*                 Registers Preserved:
;*                       BX,CX,SI,DI,BP
;*                 Registers Destroyed:
;*
;* INPUT         = BX = Start X (left) of rectangle
;*                 CX = Start Y (top) of rectangle
;*                 SI = Width of rectangle
;*                 DI = Height of rectangle
;*                 Hardware clip rectangle already set
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing
        
                public opaque_8514
opaque_8514      proc near

;/*
;** CAUTION: WaitQ and outwQ macros use AX and DX!  Don't put anything precious
;** in them.
;*/

        WaitQ   8                       ; Wait for an empty queue
        outwQ   X0,bx                   ; Inform board of starting X
        outwQ   Y0,cx                   ; Inform board of starting Y
        mov     ax,si                   ; Width
        dec     ax                      ; 8514 wants width-1
        outwQ   LX                      ; Inform board of width
        mov     ax,di                   ; Height
        dec     ax                      ; 8514 wants height-1
        .errnz  LY_2DECODE
        outwQ   LY                      ; Inform board of height
        mov     ax,colors               ; AH=background color; AL=text color
        shr     ax,8                    ; AL=background color; AH=0
        outbQ   COLOR_1                 ; Inform board of color to use
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_S); Use solid pattern, reference COLOR 1
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES); Fill with solid pattern, reference FUNCTION 1
        outwQ   CMD_FLAGS,<(CMD_C_HRECT+CMD_FV_FIX+CMD_DY+CMD_DX+CMD_MA_ACCESS+\
                CMD_PA_FOUR+CMD_RW_W)>
        ret
opaque_8514      endp
        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 = CX = 0 if recursing
;*                 CX = 1 if not recursing
;*
;* RETURN-ERROR  = to exit_strblt_error if device isn't enabled
;*
;**************************************************************************/

        assumes ds,Data
        externW CodeData


        assumes ds,nothing
        assumes es,nothing

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 proc near

        lds     si,lp_device
        test    [si].sd_fb,SD_DEVICE
        jz      v_gdd_dev_is_bitmap
        or      excel,IS_DEVICE

;/*
;**     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
;**     8514'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     cx,o_rect.rcs_pts1.pts_x
        mov     dx,o_rect.rcs_pts1.pts_y
        mov     si,o_rect.rcs_pts2.pts_x
        mov     di,o_rect.rcs_pts2.pts_y
        jmp     short gdd_exclude_have_rect


gdd_exclude_text_or_both:
        mov     ax,text_bbox.rcs_pts1.pts_x;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    cx,ax
        mov     ax,text_bbox.rcs_pts2.pts_x;Clip text right to screen right
        smin_ax SCREEN_CX                         ; !!! Can't be absolute.  There are other resolutions
        xchg    ax,si                   ;SI is now rhs
        mov     dx,text_bbox.rcs_pts1.pts_y
        mov     di,text_bbox.rcs_pts2.pts_y
        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     bx,dx                   ;BX = text_bbox.rcs_pts1.pts_y
        mov     ax,o_rect.rcs_pts1.pts_y
        smin_ax bx
        xchg    bx,ax
        mov     ax,o_rect.rcs_pts1.pts_x
        smin_ax cx
        xchg    ax,cx
        mov     ax,o_rect.rcs_pts2.pts_x
        smax_ax si
        xchg    si,ax
        mov     ax,o_rect.rcs_pts2.pts_y
        smax_ax di
        xchg    ax,di
        mov     dx,bx

gdd_exclude_have_rect:
        dec     si                      ;Want rhs and bottom to be inclusive
        dec     di
        call    far_exclude

;/*
;** Exclusion has been handled.  Now initialize some of the frame variables
;** for the 8514 and cache the current font for speedy 8514 access.  The
;** cache is an on-demand cache, loaded only when there is a string to
;** display.
;*/

        mov     ax,clipped_font_height
        mov     cell_adjust,ax
        mov     opaque_routine,CodeOFFSET opaque_8514
        mov     bx,colors
        and     bx,MM_ALL shl 8 + MM_ALL; Clear upper nibbles if low res
        mov     colors,bx
        missing_code    <This is where tonys_bar_n_grill is initialized.>
        errnz   BACKGROUND-1
        and     excel,not CACHED_FONT   ; Assume font won't be cached
        test    excel,TEXT_VISIBLE      ; Don't cache if no visible text
        jz      gdd_cache_exit          ;   ('test' opcode clears 'C' flag)

        GrabScreen  strdraw             ; don't let cursor interfere

        mov     ds,CodeData
        assumes ds,Data
        call    cache_font

gdd_cache_exit:
        mov     cx,1                    ; Not recursing
        ret


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

        assumes ds,nothing
        assumes es,nothing


gdd_dev_is_bitmap:
        test    [si].sd_fb,SD_HUGE      ;If huge bitmap,    s non-zero,
        jnz     gdd_huge_bitmap         ;  then handle separately

gdd_small_bitmap:
        mov     ax,[si].sd_pBits.sel
        mov     seg_lp_surface,ax

gdd_finish_bitmap:                      ;Huge bitmap code can jump here
        mov     ax,[si].sd_pBits.off
        mov     off_lp_surface,ax
        mov     ax,[si].sd_cbScan
        mov     next_plane,ax
        mov     ax,[si].sd_dScan
        mov     next_scan,ax
        mul     clipped_font_height     ;Compute adjustment from bottom
        dec     ax                      ;  of character to top of
        mov     cell_adjust,ax          ;  next character

        mov     dx,CodeOFFSET color_bitmap_opaque
        mov     cl,0ffh                 ; Color bitmaps represented with 0ffh
        mov     ax,colors
        test    [si].sd_fb,SD_COLOR
        jnz     gdd_is_color_bitmap

        mov     cl,1                    ;1 plane
        mov     dx,CodeOFFSET mono_bitmap_opaque

        lds     si,lp_DDC               ; Need DDC ptr for IPC access
        assumes ds,nothing
        add     si,npAttrs              ; -> ddc_ca or ddc_ma

        mov     ah,[si].ca_ba.ba_ipcBack.ipc_bStatus; fetch bg MONO_BIT
        mov     al,[si].ca_ba.ba_ipc.ipc_bStatus; fetch fg MONO_BIT
        and     ah,(MONO_BIT shr 8)     ; isolate the bg MONO_BIT
        and     al,(MONO_BIT shr 8)     ; isolate the fg MONO_BIT
        .errnz  (high MONO_BIT) - 1
        mov     colors,ax

;/*
;**     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.
;**
;**     This applies only to the MONO_BITS for a monochrome bitmap and
;**     when the background mode is OPAQUE.
;*/

        mov     ch,accel
        test    ch,IS_OPAQUE            ; In opaque mode?
        jz      gdd_is_color_bitmap     ; No, don't set up special color.
        test    ch,IS_XOR_TEXT
        jnz     gdd_mbm_get_color
        test    ch,IS_OR_TEXT
        jnz     gdd_mbm_set_or

gdd_mbm_xor_color:
        xor     al,ah

gdd_mbm_get_color:
        shr     ah,1                    ; Backgound MONO_BIT
        rcl     bl,1                    ; Put the bit in its place
        shr     al,1                    ; Foreground MONO_BIT
        rcl     bl,1                    ; Put the bit in its place
        mov     special_bm_opaque_color,bl ; Remember the more useful form
        jmp     short gdd_is_color_bitmap

gdd_mbm_set_or:
        or      al,ah                   ;OR background into foreground
        jmp     gdd_mbm_xor_color

gdd_is_color_bitmap:
        mov     opaque_routine,dx
        mov     num_planes,cl
        mov     cx,1
        clc
        ret


;/*
;**     This is a huge bitmap.  If the text or opaque rectangle
;**     spans a segment boundary, then we'll recurse (curse?) to
;**     handle the string, setting a clipping rectangle which is
;**     appropriate for each 64K segment of the string.
;**
;**     Both the opaque rectangle and the text bounding box have
;**     already been clipped in Y to the actual clipping rectangle,
;**     so we are guaranteed not to overflow the real clipping
;**     rectangle's Y range.
;*/

gdd_huge_bitmap:
        mov     al,excel                ;If we have both, then the union
        not     al                      ;  of the two will be needed
        and     al,OPAQUE_RECT+TEXT_VISIBLE
        mov     ax,text_bbox.rcs_pts1.pts_y
        mov     bx,text_bbox.rcs_pts2.pts_y
        mov     cx,o_rect.rcs_pts1.pts_y
        mov     di,o_rect.rcs_pts2.pts_y
        jnz     gdd_dont_do_union       ;Only have one rectangle
        smin_ax cx
        xchg    ax,bx
        smax_ax di
        xchg    ax,bx                   ;AX = top, BX = bottom
        jmp     short gdd_have_y_ext

gdd_dont_do_union:
        test    excel,TEXT_VISIBLE      ;Y top and bottom for text only
        jnz     gdd_have_y_ext          ;  is already set in AX, BX
        xchg    ax,cx                   ;Need Y top and bottom for the
        xchg    bx,di                   ;  opaque rectangle

gdd_have_y_ext:
        mov     clip.rcs_pts2.pts_y,bx          ;Save bottom and top incase
        mov     clip.rcs_pts1.pts_y,ax             ;  we cross a segment
        mov     di,[si].sd_cySeg        ;#  of scanlines in each segment
        xor     dx,dx                   ;Compute segment and starting
        div     di                      ;  scan of top line
        xchg    ax,bx
        mov     cx,dx
        xor     dx,dx                   ;Compute segment and scan of the
        dec     ax                      ;  last line (want the calc to be
        div     di                      ;  inclusive of last line).


;/*
;**     We now have the following information:
;**
;**         BX = segment number of the starting scan line
;**         CX = starting scan line within the segment
;**         AX = segment number of the last scan line
;**         DX = ending scan line within the segment
;**         DI = # scans per segment
;**
;**     If everything is contained within one segment, then we blow
;**     off the recursion and just output the stuff.  If seperate
;**     segments are involved, we dummy up a clip rectangle and
;**     call ourselves again.  If only one segment is involved,
;**     we just alter the Y values a little to adjust for the actual
;**     segment, and pretend we're a small bitmap.
;*/

        cmp     ax,bx
        jne     gdd_different_segments
        or      ax,ax                   ;If in first segment, don't need
        jz      gdd_have_segment        ;  to adjust Y values
        mul     di                      ;Compute the number of scans to
        sub     text_bbox.rcs_pts1.pts_y,ax ;  subtract off of the original
        sub     text_bbox.rcs_pts2.pts_y,ax ;  Y's to bring them within the
        sub     o_rect.rcs_pts1.pts_y,ax    ;  allowable range for this segment
        sub     o_rect.rcs_pts2.pts_y,ax
        mov     ax,[si].sd_selIncr      ;Compute the adjustment to the
        mul     bx                      ;  selector

gdd_have_segment:
        add     ax,[si].sd_pBits.sel    ;Save pointer to the bits
        mov     seg_lp_surface,ax
        jmp     gdd_finish_bitmap


gdd_different_segments:
        push    clip.rcs_pts2.pts_y             ;Save until we need it

;/*
;**     We now have the following information:
;**
;**     BX = segment number of the starting scan line
;**     CX = starting scan line within the segment
;**     AX = segment number of the last scan line
;**     DX = ending scan line within the segment
;**     DI = # scans per segment
;*/

        sub     ax,bx                   ;Number of times we'll make the call
        xchg    ax,si                   ;Keep count in SI
        xchg    ax,bx                   ;Get segment index of first scan
        inc     ax
        mul     di                      ;Compute end of first segment

gdd_do_next_whole_segment:
        mov     clip.rcs_pts2.pts_y,ax

gdd_do_last_segment:

        lea     ax,clip
        farPtr  lp_new_clip_rect,ss,ax
        mov     cl,1                    ;String translation flag - translate
        arg     lp_DDC                  ;DDC
        arg     lp_device               ;Destination device
        arg     x                       ;Left origin of string
        arg     y                       ;Top  origin of string
        arg     lp_new_clip_rect        ;Clipping rectangle
        arg     lp_string               ;The string itself
        arg     count                   ;Number of characters in the string
        arg     npAttrs                 ;Attribute bundle to use
        arg     lp_dx                   ;Widths for the characters
        arg     lp_opaque_rect          ;Opaquing rectangle
        arg     eto_options             ;ExtTextOut options
        cCall   InternalExtTextOut


;/*
;**     If all went well, the first portion of the text has been
;**     displayed.  Let's just keep doing it until we've done all
;**     remaining segments.
;*/

        mov     ax,clip.rcs_pts2.pts_y          ;Set start of next segment
        mov     clip.rcs_pts1.pts_y,ax
        add     ax,di
        dec     si
        jg      gdd_do_next_whole_segment


;/*
;**     A little slime here folks.  The first time we'll pop the real
;**     bottom scan line.  The second time, we'll pop the return address.
;*/

        pop     clip.rcs_pts2.pts_y             ;Set last scan
        jz      gdd_do_last_segment
        push    clip.rcs_pts2.pts_y
        xor     cx,cx
        clc
gdd_exit:
        ret
get_device_data endp
page


sEnd    Code
        end
