;*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 = WINQUERY.ASM
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/29/90
;*
;* DESCRIPTION  This is part of the DBCS-NLS support dependent sources.
;*              This module contains the querying string size/position
;*              functions, which require special DBCS handling.
;*
;* FUNCTIONS    QueryCharPositions
;*              QueryTextBox
;*              QueryWidthTable
;*
;* NOTES        Supplied only for DBCS enabled display driver.
;*              These entries should be hooked only when the device driver
;*              provides the MBCS/DBCS device fonts.
;*              When the driver has no device font, or the driver provides only
;*              SBCS font, return CAPS_FONT_IMAGE_MANAGE flag at
;*              QueryDeviceCaps, then the Engine never call this entry so the
;*              hooking isn't needed.
;*              (this is why we need not to check swFlags.)
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/29/90                     Written by Soh Ohta and Masako Kojima.
;*
;*****************************************************************************/

        .386

        .MODEL FLAT

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

        .XLIST

INCL_GRE_FONTS          equ     1
INCL_GRE_XFORMS         equ     1
INCL_GRE_BITMAPS        equ     1
INCL_GRE_CLIP           equ     1
INCL_GRE_STRINGS        equ     1
INCL_GRE_DEVSUPPORT     equ     1
INCL_GRE_DEVMISC3       equ     1
INCL_FONTFILEFORMAT     equ     1
INCL_DDIMISC            equ     1
INCL_DEV                equ     1
INCL_DDIBUNDLES         equ     1
INCL_DDICOMFLAGS        equ     1

INCL_DDIFONTSTRUCS EQU 1

        OPTION  OLDSTRUCTS

        include pmgre.inc

DINCL_ENABLE            equ     1
DINCL_VIO               equ     1
DINCL_BITMAP            equ     1

        include driver.inc
        include oemblt.inc
        include fontseg.inc
        include extern.inc
        include protos.inc
        include bsememf.inc

KC_DBCSRSRVD2       equ     0           ; unresolved but not used.

        .LIST

;       ??_out  winquery

;       errcode <INV_IN_PATH,BITMAP_NOT_SELECTED,INV_LENGTH_OR_COUNT,INV_FIRST_CHAR>

        .DATA

align 4
ArrayConvTable2  dd 512  dup (?)
exttextout_args  db size eto_args dup (?)

        .CODE

page

;--------------------------Exported-Routine-----------------------------;
; QueryCharPositions
;
; Returns the positions of the characters in the lpXY array.
; The lpXY has N + 1 positions so the first contains the
; current position and the last contains the new current position.
;
; Entry:
;       None
; Returns:
;       EAX = 1
; Error Returns:
;       EAX = 0
; Registers Destroyed:
;       EAX,EBX,ECX,EDX
; History:
;  Jun 30  1992                 -by-    Hide Muta       [jl25345@ymtvm3]
; Modified for 32 bit model.
;  Nov 29, 1990                 -by-    Soh Ohta        [jl09057@ymtvm3]
; Add DBCS enabling.
;  Mon Jun 13, 1988 14:48:00    -by-    Kent Settle     [kentse]
; Cleaned up error handling.
;  Sat Mar 06 17:01:21 1988     -by-    Mike Harrington [mikehar]
; Made the returned box current position relative.
;  Mon Nov 09 10:39:31 1987     -by-    Hock Lee        [hockl]
; Added lpStartXY parameter.
;  Thu Jul 16 09:22:32 1987     -by-    Hock Lee        [hockl]
; Modified for new DDI.
;  Sat Jun 20 18:22:23 1987     -by-    Hock Lee        [hockl]
; Wrote it.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; QueryCharPositions - DBCS Enabled PDI Function Entry
;
;   Stores an array of world coordinates identifying the start points
;   at which the device is to place each character of given string.
;
; DBCS handling:
;
;   Handles DBCS character as one character. For this, if the character
;   is in the DBCS leading byte code-point range, also fetchs the DBCS
;   trailing byte and process them at once.
;
;   THIS IS NOT TRUE SPEC**********************************************
;   The start coordinate of DBCS trailing byte will be set to the equal
;   position of DBCS leading byte.
;   (DONT_TOUCH_DBCS_TRAILING = 0)
;
;   CORRECT SPEC*******************************************************
;   The start coordinate of DBCS trailing byte is unknown. Nothing will
;   be stored into charpos for DBCS trailing byte (not touched).
;   (DONT_TOUCH_DBCS_TRAILING = 1)
;
; Special Cases:
;
;   Under the MBCS codepage, the DBCS leading byte at the end of string
;   will be treated as SBCS (invalid) code-point.
;-----------------------------------------------------------------------;

DONT_TOUCH_DBCS_TRAILING    equ     0   ; incorrect but WinDrawText assume this.

;       check   QueryCharPositions,<hdc,pptlStart,flCmd,cch,pch,pdx,pptlCharPos,hddc,ulFunN>

QueryCharPositions PROC SYSCALL,
                hdc        :DWORD,
                lpStartXY  :DWORD,
                Options    :DWORD,
                N          :DWORD,
                lpCh       :DWORD,
                lpDx       :DWORD,
                lpXY       :DWORD,
                hddc       :DWORD,
                FunN       :DWORD
        LOCAL   nCharsLeft :DWORD,
                wDirection :DWORD,
  EspSave    :DWORD,
                StartXY    :POINTL

        push    esi
        push    edi
        push    ebx
 mov EspSave,esp

        cld
        mov     esi,hddc
 mov     edx,esi
        INVOKE  enter_driver

; make sure its not a vector font

        test    FunN,COM_DEVICE
        jnz     stay_away_from_engine   ; we are forced to go through with it.
        test    [esi].ddc_fb,DDC_UNIT_XFORM
        jz      travel_toward_engine
        test    [esi].ddc_ca.ca_fs,CA_VECTOR+CA_PREC_NOT_1+CA_STRIKEOUT+CA_UNDERSCORE+CA_ITALIC+CA_BOLD\
      ;         +CA_DIRECTION           ; <== we can handle it (DBCS ok!)
        jz      stay_away_from_engine   ; we can handle it

; redispatch to engine

travel_toward_engine:
        INVOKE  leave_driver

        pop     ebx
        pop     edi
        pop     esi
        mov     esp,ebp
        pop     ebp                     ; cleanframe
        jmp     pfnDefQueryCharPositions; pass it back to the engine

stay_away_from_engine:

        movzx   ecx,N.hi
        jcxz    qcp_count_good
        mov     eax,PMERR_INV_LENGTH_OR_COUNT
        save_error_code
        xor     eax,eax
        jmp     qcp_exit


qcp_count_good:
        mov     ecx,N
        mov     nCharsLeft,ecx

        test    ecx,ecx
        jnz     not_null_string

; no string so just return current position.

        mov     edi,lpXY

; assume no start position

        mov     esi,[esi].ddc_prddc
        lea     esi,[esi].rddc_ptlWorldPos

        test    Options,CHS_START_XY; is there a start position?
        jz      copy_cp
        mov     esi,lpStartXY
copy_cp:
        mov     ecx,(SIZE POINTL) / 4
        rep     movsd

        mov     eax,1                   ; indicate success.
        jmp     qcp_exit

not_null_string:

        mov     eax,[esi].ddc_ca.ca_fs  ; wDirection = char_direction-1
        and     eax,CA_DIRECTION
        mov     wDirection,eax

; fill arguments to ExtTextOut

        lea     edi,exttextout_args
        .errnz  (SIZE eto_args) and 3
        mov     ecx,(SIZE eto_args) / 4
        xor     eax,eax
        rep     stosd

        mov     eax,lpCh               ; lpString
        mov     exttextout_args.eto_lpString,eax
        mov     exttextout_args.eto_lpDDC,esi
        mov     exttextout_args.eto_count,-1    ; one character at a time
        mov     exttextout_args.eto_npAttrs,ddc_ca

; get start position if one exists

        mov     edi,[esi].ddc_prddc
        mov     eax,[edi].rddc_ptsCurPos.ptl_x    ; assume current position
        mov     edx,[edi].rddc_ptsCurPos.ptl_y
        mov     StartXY.ptl_x,eax
        mov     StartXY.ptl_y,edx
        test    Options,CHS_START_XY    ; is there a start position?
        jz      got_start_position      ; no...

; copy start position

        push    esi

        mov     esi,lpStartXY
        lea     edi,StartXY
        mov     ecx,(SIZE POINTL) / 4
        rep     movsd

        pop     esi

        test    FunN,COM_TRANSFORM   ; want to transform?
        jz      got_start_position      ; no...

; transform start position

        lea     edx,StartXY
        INVOKE  convert_world_screen, edx, 1 ; esi = ddc
        or      ax,ax
        jz      qcp_exit                ; error logged by convert!
got_start_position:

; allocate space for vector if exists

        xor     eax,eax
        test    byte ptr Options,CHS_VECTOR
        jz      got_vector

        mov     eax,lpDx

; allocate space from stack

        mov     ecx,N
 lea edi,ArrayConvTable2
;       shl     ecx,2
;       sub     esp,ecx                 ; allocate space for widths
;       mov     edi,esp                 ; EDI = lpWx

;       shr     ecx,2                   ; ECX = count
 INVOKE ConvertList32, eax, edi, esi, ecx
     ; !! dword -> dword !!
        or      ax,ax
        jz      qcp_exit                ; error logged by convert!

        mov     ebx,N
 shl ebx,2
        xor     edx,edx
        test    [esi].ddc_ca.ca_fs,CA_CHAR_EXTRA
        jz      strip_neg_offsets
        mov     edx,[esi].ddc_ca.ca_cExtraPels
        neg     edx
strip_neg_offsets:
        movsx   eax,word ptr [ebx][edi][-4]
        or      eax,eax
        jns     strip_loop
        smax_ax edx
        mov     [ebx][edi][-4],eax
strip_loop:
 sub ebx,4
        jnz     strip_neg_offsets


        mov     eax,edi

got_vector:

        mov     exttextout_args.eto_lpDX,eax

; get text extent for each character

        mov     edi,lpXY                 ; EDI = lpXY

        mov     eax,StartXY.ptl_x        ; fill in first position
        stosd
        mov     eax,StartXY.ptl_y
        stosd

next_char_pos_loop:
        push    edi                      ; EDI = next lpXY
        push    esi


; DBCS CODEPAGE SUPPORT:
; Fix cch (count char) to 2 when the codepoint is DBCS leading byte,
; and the DBCS trailing byte exists.
; Be sure that here the cch is negative value to notify "only compute"
; to ExtTextOut.

        mov     edi,exttextout_args.eto_lpString
        xor     eax,eax
        mov     al,[edi]
        mov     ebx,eax

        mov     edi,hddc
        mov     eax,-1                          ; assumes SBCS codepage/code-point
        test    [edi].ddc_ca.ca_fsNls,NLSCA_SBCS
        jnz     single_byte                     ; SBCS codepage...
        test    [edi].ddc_ca.ca_fsNls,NLSCA_DBCS
        jnz     double_byte                     ; DBCS codepage...

        mov     edi,[edi].ddc_ca.ca_paus        ; MBCS. get translation vector
        cmp     [edi].cmt_DBCSLeading[ebx],0    ; SBCS code-point ?
        je      single_byte                     ; yes...
double_byte:
        cmp     nCharsLeft,1                    ; DBCS code-point at end of string ?
        jbe     single_byte                     ; yes...
        dec     eax
single_byte:
        mov     exttextout_args.eto_count,eax   ;-1 (SBCS) or -2 (DBCS)


; get the arguments onto our stack

        sub     esp,SIZE eto_args
        mov     edi,esp
        lea     esi,exttextout_args
        .errnz  (SIZE eto_args) and 3
        mov     ecx,(SIZE eto_args) / 4
        cld
        rep     movs dword ptr [edi],dword ptr [esi]

; make the exttextout call

        call    ExtTextOut                      ; DX = Height, AX = Extent
        ADD     ESP,SIZE eto_args
        xchg    eax,ebx                         ; we need concatenation point
        pop     esi
        pop     edi

        or      eax,eax                         ; can't be neg (yet)
        jg      concat_ok
        neg     eax
concat_ok:

        mov     ebx,wDirection
        test    ebx,1
        jnz     vertical_direction
        or      ebx,ebx
        jz      no_negate_x
        neg     eax
no_negate_x:
        xor     edx,edx
        jmp     fill_current_position

vertical_direction:
        cmp     ebx,3                           ; bottom to top?
        jz      no_negate_y
        neg     edx
no_negate_y:
        xor     eax,eax

; we have EAX = delta x, EDX = delta y for the next current position
; need to take lpDx into account too!!!

fill_current_position:

        mov     ecx,edx                         ; ECX = delta y
        add     eax,[edi][-8]                   ; new current x
        stosd

        mov     eax,ecx
        add     eax,[edi][-8]                   ; new current y
        stosd

        inc     exttextout_args.eto_lpString[0]; next character


; DBCS CODEPAGE SUPPORT:
; When DBCS trailing byte exists, the trailing byte position is unknown.
; position to the leading byte. We will skip trailing byte processing.

        cmp     exttextout_args.eto_count,-1   ; SBCS code-point processed ?
        je      sbcs_ext                       ; yes...

        inc     exttextout_args.eto_lpString[0]; next char

if DONT_TOUCH_DBCS_TRAILING

        add     edi,SIZE POINTL          ; skip charpos for DBCS trailing byte

else ; not DONT_TOUCH_DBCS_TRAILING

; Make trailing byte position equal to the leading byte position.
; This isn't the correct specification.

        mov     eax, [edi][-8]
        stosd
        mov     eax, [edi][-8]
        stosd

endif; not DONT_TOUCH_DBCS_TRAILING

        cmp     word ptr exttextout_args.eto_lpDX[0],0
        jz      no_width_vector
        add     word ptr exttextout_args.eto_lpDX[0],4  ; next width
sbcs_ext:


        cmp     word ptr exttextout_args.eto_lpDX[0],0
        jz      no_width_vector
        add     word ptr exttextout_args.eto_lpDX[0],4  ; next width
no_width_vector:
        dec     nCharsLeft
        jz      no_more_char_left


; DBCS CODEPAGE SUPPORT:
; Here count up the number of CHARACTERS (not bytes) which has been processed.

        cmp     exttextout_args.eto_count,-1    ; SBCS code-point processed ?
        je      next_char_pos_loop_relay        ; yes...
        dec     nCharsLeft                      ; DBCS code-point processed.
        jz      no_more_char_left
next_char_pos_loop_relay:
        jmp     next_char_pos_loop
no_more_char_left:

; transform the points if necessary

        mov     eax,1                   ; assume good exit.
        test    FunN,COM_TRANSFORM   ; want to transform?
        jz      qcp_exit                ;   no

        mov     eax,N
        inc     eax
        INVOKE  convert_screen_world, lpXY, eax  ; esi = ddc

qcp_exit:
        INVOKE  leave_driver
        mov     ecx,eax

 mov esp,EspSave
        pop     ebx
        pop     edi
        pop     esi
        ret
QueryCharPositions ENDP

page

;--------------------------Exported-Routine-----------------------------;
; QueryTextBox
;
; This  processes the specified string as if it were to be drawn, using the
; current character attributes, and returns an array of  5  x,y  coordinate
; pairs.  The first four of these are the coordinates of the top-left, bot-
; tom-left,  top-right  and bottom-right corners of the parallelogram which
; encompasses the string when drawn on the associated device.    The fifth
; point  is the concatenation point, that is the position at which a subse-
; quent string would have to be drawn if it were to follow on smoothly.
;
; All coordinates are relative to the start point of the string, as defined
; by the character direction.
;
; Parameters
;
;       P32_CH Long pointer to the string of character codepoints.
;
;       S32_N Specifies the number of bytes in the character string.
;
;       P32_XY Long pointer to the return array of 5 x,y pairs. These
;            coordinates are in DOCS
;
;       U32_DCH A handle to a device context
;
; Entry:
;       None
; Returns:
;       AX = 1 if the function executed successfully
; Error Returns:
;       AX = 0 otherwise
; History:
;  Jun 30  1992                 -by-    Hide Muta       [jl25345@ymtvm3]
; Modified for 32 bit model.
;  Nov 29, 1990                 -by-    Soh Ohta        [jl09057@ymtvm3]
; Add DBCS enabling.
;  Mon Oct 19 10:14:32 1987     -by-    Hock Lee        [hockl]
; Returned correct value for success.
;  Sat Oct 03 15:02:12 1987     -by-    Hock Lee        [hockl]
; Returned relative coordinates instead of absolute coordinates.
;  Sat Oct 03 15:02:12 1987     -by-    Tony Pisculli   [tonyp]
; Wrote it (Months ago)
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; QueryTextBox - DBCS Enabled PDI Function Entry
;
;   Process a character sting as if it were to be drawn, and stores
;   the coordinates of current text box relative to the current position.
;
; DBCS handling:
;
;   Simple string interface. All DBCS handling will be done at the
;   lower levels.
;
; Remark:
;
;   CA_DIRECTION (not reft to right) string is currently not handled
;   here and we call back the Engine, because get_greatest_width()
;   cannot handle DBCS font now.
;-----------------------------------------------------------------------;

;       check   QueryTextBox,<hdc,cch,pch,cptlTextBox,pptlTextBox,hddc,ulFunN>

QueryTextBox PROC SYSCALL,
                hdc             :DWORD,
                N               :DWORD,
                lpCh            :DWORD,
                Count           :DWORD,
                lpTextBox       :DWORD,
                hddc            :DWORD,
                FunN            :DWORD
        LOCAL   max_ascent      :DWORD,
                neg_max_descent :DWORD,
                neg_max_down    :DWORD,
                leftx           :DWORD,
                old_stack       :DWORD,
                ggwlpfont       :DWORD,
                ggwlpCP         :DWORD,
                ggwwidth        :DWORD,
                ptzero          :POINTL

        push    esi
        push    edi
        push    ebx

        ddc?    hddc
        cld
        mov     esi,hddc
        mov     edx,esi
        INVOKE  enter_driver

; make sure its not a vector font

        test    FunN,COM_DEVICE
        jnz     we_can_handle_it        ; we are forced to go through with it.
        test    [esi].ddc_fb,DDC_UNIT_XFORM
        jz      head_toward_engine
        test    [esi].ddc_ca.ca_fs,CA_VECTOR+CA_PREC_NOT_1+CA_STRIKEOUT+CA_UNDERSCORE+CA_ITALIC+CA_BOLD\
                +CA_DIRECTION           ; <== DBCS enabling not completed.
        jz      we_can_handle_it        ; we can handle it

; redispatch to engine

head_toward_engine:
        INVOKE  leave_driver
        pop     ebx
        pop     edi
        pop     esi
        mov     esp,ebp
        pop     ebp                     ; cleanframe
        jmp     pfnDefQueryTextBox      ;Pass it back to the engine

we_can_handle_it:

        movzx   ecx,N.hi
        jcxz    qtb_count_good
        mov     eax,PMERR_INV_LENGTH_OR_COUNT
        save_error_code
        xor     eax,eax
        jmp     qtb_exit


qtb_count_good:

; ExtTextOut ignores lpDevice, x and y in computing the text extents.
; jump past to other method if we're doing horz strings

        test    [esi].ddc_ca.ca_fs,1     ;!!! there are equates for this
        jnz     qtb_do_vertical
        jmp     qtb_use_default_dir

; do vertical strings

qtb_do_vertical:
        xor     eax,eax
        mov     leftx,eax
        mov     neg_max_descent,eax
        mov     neg_max_down,eax

; allocate space for current positions

        mov     ecx,N                ; N + 1 current positions
        inc     ecx
        shl     ecx,3
        .errnz  (SIZE POINTL) - 8
        mov     old_stack,ecx
        sub     esp,ecx
        mov     ebx,esp                 ; ebx -> points
        mov     edi,ebx                 ; save our pointer

; get current positions for all characters

;       check   QueryCharPositions,<hdc,pptlStart,flCmd,cch,pch,pdx,pptlCharPos,hddc,ulFunN>
        INVOKE  QueryCharPositions,
                hdc,
                0,
                0,
                N,
                lpCh,
                0,
                ebx,
                hddc,
                FunN

; want current positions in device space!!!

        mov     ebx,N                ; N + 1 points
        inc     ebx
        INVOKE  convert_world_screen, edi, ebx   ; esi = ddc

; Let's get the vertical string length

        mov     ebx,N
        shl     ebx,3
        mov     eax,[ebx][edi].ptl_y
        sub     eax,[edi].ptl_y
        jns     qtb_ttob
        mov     neg_max_descent,eax
        mov     neg_max_down,eax
        xor     eax,eax
qtb_ttob:
        mov     max_ascent,eax
        mov     ebx,old_stack           ; clean stack
        add     esp,ebx

        mov     edi,[esi].ddc_ca.ca_pFont
        movzx   edx,[edi].FOCAFONT.ff_fmMetrics.foca_yMaxDescender
        neg     edx
        add     neg_max_descent,edx

; returns the width of the box in bx

        push    esi                     ; Hei Mike!
        call    get_greatest_width      ; <== DBCS enabling not completed.
        pop     esi
        jmp     qtb_left_to_right

qtb_use_default_dir:
        xor     eax,eax                 ; EAX = handy zero
                                        ; (in case we skip call to ExtTextOut)
        mov     ecx,N                   ; CX = number of chars
        neg     ecx                     ; signify text extent call
        jcxz    got_extents

        push    esi                     ; save DDC around ExtTextOut

        INVOKE  ExtTextOut,
                esi, eax, eax, eax, eax, lpCh,
                ecx, ddc_ca, eax, eax, eax

        pop     esi                     ; restore ESI = DDC
got_extents:

; ExtTextOut returns DX = y extent, AX = x extent

        mov     edi,[esi].ddc_ca.ca_pFont
        movsx   ebx,[edi].FOCAFONT.ff_fmMetrics.foca_yMaxAscender
        movsx   edx,[edi].FOCAFONT.ff_fmMetrics.foca_yMaxDescender
        neg     edx

        mov     neg_max_descent,edx
        mov     max_ascent,ebx
        mov     ebx,eax

;--------------------------------------------------------------------------;
;               |------x_extent---------|
;
; (tl.x, tl.y)  *-----------------------* (tr.x, tr.y)          -
;               |                       |                       |
;               |                       |                       |
; (cp.x, cp.y)  *-------baseline--------* (fp.x, fp.y)        y_extent
;               |                       |                       |
; (bl.x, bl.y)  *-----------------------* (br.x, br.y)          -
;--------------------------------------------------------------------------;

        xor     eax,eax
        mov     leftx,eax               ;assume ltor

        mov     eax,[esi].ddc_ca.ca_fs
        and     eax,CHDIRN_RIGHTLEFT
        .errnz  CHDIRN_RIGHTLEFT-3
        jz      qtb_left_to_right
        neg     ebx
        mov     leftx,ebx
        xor     ebx,ebx

qtb_left_to_right:

; top left

        mov     ecx,Count
        dec     ecx
        js      exit_query_text_box


        mov     edi,lpTextBox

        mov     eax,leftx
        stosd

        mov     eax,max_ascent                  ; EAX = tl.y[0]
        stosd

; bottom left

        dec     ecx
        js      exit_query_text_box

        mov     eax,leftx
        stosd

        mov     eax,neg_max_descent             ; EAX = bl.y[0]
        stosd

; top right

        dec     ecx
        js      exit_query_text_box

        mov     eax,ebx                         ; EAX = tr.x[0]
        stosd

        mov     eax,max_ascent                  ; EAX = tr.y[0]
        stosd

; bottom right

        dec     ecx
        js      exit_query_text_box

        mov     eax,ebx                         ; EAX = br.x[0]
        stosd

        mov     eax,neg_max_descent             ; EAX = br.y[0]
        stosd

;       final point

        dec     ecx
        js      exit_query_text_box

        test    [esi].ddc_ca.ca_fs,1
        jz      qtb_cont_rtol
        xor     ebx,ebx
        mov     ecx,max_ascent
        mov     eax,[esi].ddc_ca.ca_fs
        and     eax,CHDIRN_BOTTOMTOP-1
        cmp     eax,CHDIRN_BOTTOMTOP-1
        jz      qtb_last_point
        mov     ecx,neg_max_down
        jmp     qtb_last_point
qtb_cont_rtol:
        xor     ecx,ecx
        or      ebx,ebx                         ; are we rtol?
        jnz     qtb_last_point
        mov     ebx,leftx

qtb_last_point:
        mov     eax,ebx
        stosd

        mov     eax,ecx
        stosd

exit_query_text_box:
        mov     eax,1
        test    FunN,COM_TRANSFORM
        jz      qtb_exit

        mov     esi,hddc              ; ESI = DDC
        xor     eax,eax
        lea     edi,ptzero
        mov     ptzero.ptl_x,eax
        mov     ptzero.ptl_y,eax
        INVOKE  convert_screen_world, edi, 1
        or      eax,eax
        jz      qtb_exit

qtb_transform:
        mov     ebx,Count
        mov     edi,ebx
        INVOKE  convert_screen_world, lpTextBox, ebx
        or      eax,eax
        jz      qtb_exit

        mov     ecx,edi
        mov     edi,lpTextBox
qtb_trans:
        mov     eax,ptzero.ptl_x
        sub     [edi].ptl_x,eax
        mov     eax,ptzero.ptl_y
        sub     [edi].ptl_y,eax
        dec     ecx
        jz      qtb_exit_good
        add     edi,size POINTL
        jmp     qtb_trans
qtb_exit_good:
        mov     eax,1
qtb_exit:

        invoke  leave_driver
        mov     ecx,eax

        pop     ebx
        pop     edi
        pop     esi
        ret
QueryTextBox ENDP

page

;-----------------------------------------------------------------;
; get_greatest_width
;
; This function returns the max width of the characters in the
; string in ebx.
;
;Entry:
;  Frame as per QuertyTextBox
;  esi -> font
;Returns:
;  ebx = max width
; Registers Destroyed:
;   Flags,EAX,EBX,ECX,EDX,EDI
; History:
;  Jun 30  1992               -by-   Hide Muta       [jl25345@ymtvm3]
; Modified for 32 bit model.
;  Wed 30-Mar-1988 14:50:05   -by-   Mike Harrington [mikehar]
; Wrote it.
;-----------------------------------------------------------------;
GGW_CP  equ     1
GGW_ABC equ     2

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

get_greatest_width PROC SYSCALL,
                hdc             :DWORD,
                N               :DWORD,
                lpCh            :DWORD,
                Count           :DWORD,
                lpTextBox       :DWORD,
                hddc            :DWORD,
                FunN            :DWORD
        LOCAL   max_ascent      :DWORD,
                neg_max_descent :DWORD,
                neg_max_down    :DWORD,
                leftx           :DWORD,
                old_stack       :DWORD,
                ggwlpfont       :DWORD,
                ggwlpCP         :DWORD,
                ggwwidth        :DWORD,
                ptzero          :POINTL

        xor     ebx,ebx           ;start with 0 width
        mov     ggwwidth,ebx
        test    [esi].ddc_ca.ca_fs,CA_FIXED_PITCH+CA_WIDTH_IS_8
        jz      ggw_not_eight
        mov     ebx,8
        jmp     ggw_exit
ggw_not_eight:
        mov     ecx,N
        jcxz    ggw_exit2
        test    [esi].ddc_ca.ca_fs,CA_FIXED_PITCH
        jz      ggw_no_fp
        mov     ecx,1
ggw_no_fp:
        xor     edx,edx         ;use for code page flag
        test    [esi].ddc_ca.ca_fs,CA_MUST_MAP
        jz      ggw_init
        mov     edx,GGW_CP       ;non-zero
        mov     edi,[esi].ddc_ca.ca_paus
        mov     ggwlpCP,edi
ggw_init:
        mov     edi,[esi].ddc_ca.ca_pFont
        mov     ggwlpfont,edi
        mov     esi,lpCh
        xor     eax,eax
ggw_loop:
        lodsb
        test    edx,GGW_CP
        jz      ggw_no_cp
        mov     ebx,eax
        shl     ebx,1
        mov     edi,ggwlpCP
        movzx   ebx,word ptr [edi][ebx]
        mov     edi,ggwlpfont
        jmp     ggw_get_width
ggw_exit2:
        jmp     ggw_exit
ggw_no_cp:
        mov     ebx,eax
        shl     ebx,2
        add     eax,eax
        add     ebx,eax
        test    edx,GGW_ABC
        jz      ggw_get_width
        add     eax,eax
        add     ebx,eax
ggw_get_width:
        movzx   ebx,word ptr [edi][ebx][4]
        test    edx,GGW_ABC
        jz      ggw_cmp
        add     bx,word ptr [edi][ebx][6]
        add     bx,word ptr [edi][ebx][8]
ggw_cmp:
        cmp     ggwwidth,ebx
        jg      ggw_end_loop
        mov     ggwwidth,ebx
ggw_end_loop:
        loop    ggw_loop
        mov     ebx,ggwwidth
ggw_exit:
        ret
get_greatest_width ENDP

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

page

;---------------------------Public-Routine------------------------------;
; QueryWidthTable (hdc,firstChar,N,lpWidths,hddc,FunN)
;
; Returns:
;
; Error Returns:
;
; History:
;  Jun 30  1992                -by-  Hide Muta [jl25345@ymtvm3]
; Modified for 32 bit model.
;  Nov 29, 1990                -by-  Soh Ohta [jl09057 @ ymtvm3]
; Add DBCS enabling.
;  Wed 27-Jan-88 16:00:00 -by- Mike Harrington [mikehar]
; Added Codepage code.
;  Wed Jan 20, 1988 18:00:00   -by-  Mike Harrington [mikehar]
; added a,b,c spacing and debugged.
;  Thu Mar 19, 1987 12:17:56p  -by-  Paul Klingler [paulk]
; Created.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; QueryWidthTable - DBCS Enabled PDI Function Entry
;
;   Stores an array of world coordinates representing the width table
;   information of currently selected font.
;
;   The Engine never calls this entry for Engine (generic) fonts.
;   The Engine always call us with COM_DEVICE=on and COM_TRANSFORM=off,
;   so we will return the device font widths in device coordinate.
;
; DBCS handling:
;
;   Allows DBCS firstchar for MBCS/DBCS codepage. Removes firstchar
;   code-point check for these codepages.
;
;   The width table for DBCS code-points is returned for DBCS firstchar,
;   else the width table for SBCS code-points is returned.
;   Under DBCS codepage, DBCS width table will be returned anyway.
;
;   Be sure that the DBCS code-point is passed in FirstChar as follows:
;
;       FirstChar.lo[0] : DBCS leading  byte
;       FirstChar.lo[1] : DBCS trailing byte
;
; Special Cases:
;
;   The width table is filled with SBCS defaultchar, when the DBCS width
;   table is being created and the selected font doesn't have DBCS font
;   definition.
;   This is the short cut of the following steps:
;   - DBCS font is requested ... font not defined --> DBCS defaultchar
;   - DBCS defaultchar is not available           --> SBCS defaultchar
;
; Remarks:
;
;   The resulted DBCS width table doesn't skip any invalid DBCS code-
;   points, invalid DBCS trailing byte range, for example.
;   Any character-not-assigned/invalid code-points are handled as
;   undefined/invalid characters, and their widths will be returned.
;
;   Note that the valid max table length is 256 for all codepages.
;   (This is current implementation and this spec is not documented).
;-----------------------------------------------------------------------;

QueryWidthTable PROC SYSCALL,
                hdc             :DWORD,
                firstChar       :DWORD,
                N               :DWORD,
                lpWidths        :DWORD,
                hddc            :DWORD,
                FunN            :DWORD
        LOCAL   npts            :DWORD,
                codepageoffset  :DWORD,
                lcodepage       :DWORD

        push    esi
        push    edi
        push    ebx

        ddc?    hddc
        cld
        mov     esi,hddc              ; ESI = DDC
        mov     edx,esi
        INVOKE  enter_driver

; do we have work to do?

        xor     eax,eax
        cmp     N.hi,ax
        jne     qwt_log_count_error
        mov     ecx,N
        jcxz    qwt_no_cell2
        dec     ecx
        or      ch,ch                   ; Spec says max is 256
        jnz     qwt_log_count_error
        cmp     firstChar.hi,ax
        jne     qwt_bad_start_char

        test    FunN,COM_DEVICE
        jnz     things_are_great        ; we are forced to go through with it.
        test    [esi].ddc_fb,DDC_UNIT_XFORM
        jz      qwt_call_engine
        test    [esi].ddc_ca.ca_fs,CA_VECTOR+CA_PREC_NOT_1+CA_ITALIC+CA_BOLD
        jz      things_are_great

; redispatch to engine

qwt_call_engine:
        INVOKE  leave_driver
        pop     ebx
        pop     edi
        pop     esi
        mov     esp,ebp
        pop     ebp                     ; cleanframe
        jmp     pfnDefQueryWidthTable   ; pass it back to the engine

qwt_no_cell2:
        jmp     qwt_no_cell


things_are_great:

; DBCS CODEPAGE SUPPORT:
; Check the firstChar under the specified code page condition.
; Under the SBCS code page, valid firstChar range is 0..255.
; Under the MBCS/DBCS code page, valid firstChar range is 0..255
;   when the firstChar.lo[0] is not DBCS leading byte.

        mov     eax,[esi].ddc_ca.ca_lCodePage
        mov     lcodepage,eax           ; save logical codepage

        test    [esi].ddc_ca.ca_fsNls,NLSCA_SBCS
        jnz     qwt_check_firstchar
        test    [esi].ddc_ca.ca_fsNls,NLSCA_DBCS
        jnz     qwt_dbcs_firstchar

        xor     ebx,ebx
        mov     bl,byte ptr firstChar.lo[0]
        mov     edi,[esi].ddc_ca.ca_paus
        cmp     [edi].cmt_DBCSLeading[ebx],0
        je      qwt_check_firstchar     ; leading byte is SBCS code point

qwt_dbcs_firstchar:
        mov     firstChar.hi[0],1       ; DBCS firstChar flag
        jmp     qwt_firstchar_ok
qwt_check_firstchar:
        cmp     firstChar.lo[1],0
        jne     qwt_bad_start_char      ; firstChar out of range
qwt_firstchar_ok:

; do we need to mess with this code page stuff?

        xor     eax,eax                 ; assume no
        mov     codepageoffset,eax
        test    [esi].ddc_ca.ca_fs,CA_MUST_MAP
        jz      get_some_char_widths

        mov     eax,[esi].ddc_ca.ca_paus
        mov     codepageoffset,eax

get_some_char_widths:
        mov     eax,[esi].ddc_ca.ca_fsFont
        mov     esi,[esi].ddc_ca.ca_pFont
        mov     edi,lpWidths

        xor     edx,edx
        xor     ecx,ecx
        mov     npts,ecx

; DBCS CODEPAGE SUPPORT:
; If the firstChar is SBCS code-point, we will create width table for
; SBCS code points. If the firstChar is DBCS code-point and the font
; includes DBCS chatacters, the width table for DBCS code-points will
; be created. If the font doesn't include DBCS characters, the width
; table will be filled with SBCS default char width.

        cmp     firstChar.hi[0],0       ; DBCS firstChar flag
        je      qwt_get_sbcs_widths

        mov     ecx,N
        test    eax,NLSCA_FONT_SBCS
        jnz     only_bad_left           ; fill with SBCS defaultchar width

        call    get_dbcs_font_indexes
        mov     ecx,N
        mov     edi,lpWidths            ; EDI --> DBCS font index list
        INVOKE  get_some_dbcs_widths
        jmp     qwt_no_cell


qwt_get_sbcs_widths:
        cmp     codepageoffset,0        ; codepage==850 ?
        jne     no_bad_points           ; yes...

        movzx   ebx,firstChar.lo
 push eax
        movzx   eax,[esi].FOCAFONT.ff_fmMetrics.foca_usFirstChar
 sub ebx,eax
 pop eax
 jns     greater_than_first
        mov     ecx,ebx
        neg     ecx
        mov     eax,ebx
        add     eax,N
        jg      greater_than_first
        add     ecx,eax
        jmp     only_bad_left
qwt_all_chars_at_end:
        mov     npts,edx
        mov     ebx,N
        mov     npts,ebx
        jmp     nothing_past_the_end
greater_than_first:

; are all chars past the end?

        movzx   ebx,firstChar.lo
 push eax
        movzx   eax,[esi].FOCAFONT.ff_fmMetrics.foca_usLastChar
 sub ebx,eax
 pop eax
        jns     qwt_all_chars_at_end
        add     ebx,N
        dec     ebx
        or      ebx,ebx
        js      nothing_past_the_end
        mov     npts,ebx
        sub     N,ebx
nothing_past_the_end:
        jcxz    no_bad_points

; get the default Width

        add     firstChar.lo,cx
        sub     N,ecx
        js      qwt_no_cell
        push    ecx
        mov     ecx,1
        movzx   ebx,[esi].FOCAFONT.ff_fmMetrics.foca_usDefaultChar
        add     bx,[esi].FOCAFONT.ff_fmMetrics.foca_usFirstChar
        INVOKE  get_some_widths ,codepageoffset
        pop     ecx
        dec     ecx
        jcxz    no_bad_points
        mov eax,[edi][-4]          ; get moved width
bad_loop:
        rep stosd

no_bad_points:
        mov     ecx,N
        movzx   ebx,firstChar.lo
        INVOKE  get_some_widths ,codepageoffset

        mov     ecx,npts
        jcxz    qwt_no_cell
only_bad_left:
        push    ecx
        mov     ecx,1
        movzx   ebx,[esi].FOCAFONT.ff_fmMetrics.foca_usDefaultChar
        add     bx,[esi].FOCAFONT.ff_fmMetrics.foca_usFirstChar
        INVOKE  get_some_widths ,codepageoffset
        pop     ecx
        dec     ecx
        jcxz    qwt_no_cell
        mov eax,[edi][-4]          ; get moved width
bad_loop2:
        rep stosd

qwt_no_cell:
        INVOKE  leave_driver
        mov     eax,1

exit_query_width_table:
        pop     ebx
        pop     edi
        pop     esi
        ret

qwt_log_count_error:
        mov     eax,PMERR_INV_LENGTH_OR_COUNT
        jmp     qwt_log_error
qwt_bad_start_char:
        mov     eax,PMERR_INV_FIRST_CHAR
        errn$   qwt_log_error
qwt_log_error:
        save_error_code
        INVOKE  leave_driver
        xor     eax,eax
        jmp     exit_query_width_table

QueryWidthTable ENDP

page

;---------------------------Public-Routine------------------------------;
; get_some_widths
;
; Copies widths from the font to a POINTL struct setting y to 0 (width,0).
;
; Entry:
;       ecx number of characters we should get
;       esi long pointer to font
;       edi long pointer to array of points
;       ebx = firstChar; requested first character
;
; Returns:
;       nothing
; Error returns:
;       nothing
; Registers Destroyed:
;  EAX,EBX,ECX,EDX,EDI
;
; History:
;  30-Jun-1992 -by- Hide Muta [jl25345@ymtvm3]
; Modified for 32 bit model.
;  29-Nov-1990 -by- Soh Ohta [jl09057@ymtvm3]
; Got from Engine version J1.3 to correct bugs for abc fonts.
;  14-Mar-1990 -by- John Colleran [johnc]
; Moved lastchar and firstchar boundary checks into get_some_widths so checks
; are made after codepage mapping.
;  Mon 3-Oct-88 10:40:00 -by- Tom Bates [tomba]
; Fixed the codepage stuff for both regular and abc fonts.  It was full
; of bugs (about 10 -- no kidding).
;  Wed 27-Jan-88 16:00:00 -by- Mike Harrington [mikehar]
; Added Codepage code.
;  Wed 20-Jan-1988 12:35 -by- Mike Harrington [mikehar]
; Added a,b,c capabilities.
;  Sun 19-Jul-1987 07:15:05  -by-  Paul Klingler [paulk]
; Wrote it.
;-----------------------------------------------------------------------;

; ABC_FONT_ENTRIES is the format of the individual character records in
; an ABC spaced font.

ABC_FONT_ENTRIES struc
abc_fe_dBits     dd     ?
abc_a_space      dw     ?
abc_b_space      dw     ?
abc_c_space      dw     ?
ABC_FONT_ENTRIES ends

get_some_widths PROC SYSCALL uses ESI,
                gcpvector :DWORD
        LOCAL   codept    :DWORD    ; not first char relative!
        LOCAL   firstchar :DWORD,
                lastchar  :DWORD,
                defchar   :DWORD

        mov     codept,ebx
        movzx   eax,[esi].ff_fmMetrics.foca_usFirstChar
        mov     firstchar,eax
        movzx   eax,[esi].ff_fmMetrics.foca_usLastChar
        mov     lastchar,eax
        movzx   eax,[esi].ff_fmMetrics.foca_usDefaultChar
        mov     defchar,eax

; is this an a,b,c font?

        movzx   eax,[esi].ff_fdDefinitions.fdh_fsChardef
        add     esi,ff_fdDefinitions + size FONTDEFINITIONHEADER
        cmp     eax,FONTDEFCHAR3
        je      move_abc_widths

move_the_char_widths:
        mov     eax,codept
        cmp     gcpvector,0
        jz      gsw_no_cpod

; If we have to map then we want to use the codepoint directly (i.e. without
; subtracting the firstchar) for indexing into the mapping vector.  We subtract
; the firstchar after we map iff we didn't get a null from the map, in which
; case we use the default character which is already first char relative.

        add     eax,eax                 ; turn into a word offset
        mov     ebx,gcpvector
        add     ebx,eax                ; index into the mapping vector
        movzx   eax,word ptr [ebx]      ; pick up the map codepoint

; if we picked up a null, we must use the default character

        or      eax,eax
        jnz     gsw_no_cpod
gsw_use_default_char:
        mov     eax,defchar
        jmp     gsw_no_sub_first

gsw_no_cpod:
        sub     eax,firstchar
        jb      gsw_use_default_char    ; glyph not in this font! use default.
        cmp     eax,lastchar            ; last char is first char relative
        ja      gsw_use_default_char    ; glyph not in this font! use default.
gsw_no_sub_first:
        mov     ebx,eax                 ; each record is 3 words mul by 6
        shl     ebx,2
        add     eax,eax
        add     ebx,eax

move_add:
        movzx   eax,[esi][ebx].abc_a_space      ; get the width from the font
        stosd
        inc     codept
        loop    move_the_char_widths
        jmp     move_widths_exit

; handle the abc spacing case

move_abc_widths:
        mov     edx,codept
        cmp     gcpvector,0
        jz      agsw_no_cpod

        mov     ebx,gcpvector
        add     ebx,edx
        add     ebx,edx
        movzx   edx,word ptr [ebx]

; if we picked up a null, we must use the default character

        or      edx,edx
        jnz     agsw_no_cpod
agsw_use_default_char:
        mov     edx,defchar
        jmp     agsw_no_sub_first

agsw_no_cpod:
        sub     edx,firstchar
        jb      agsw_use_default_char   ; glyph not in this font! use default.
        cmp     edx,lastchar            ; last char is first char relative
        ja      agsw_use_default_char   ; glyph not in this font! use default.
agsw_no_sub_first:
        mov     ebx,edx                 ; abc record is 5 words so mul by 10
        shl     ebx,3
        add     ebx,edx
        add     ebx,edx

abc_add:
        movzx   eax,[esi][ebx].abc_a_space        ; get a
        add     ax,[esi][ebx].abc_b_space         ; add in b
        add     ax,[esi][ebx].abc_c_space         ; add in c
        stosd
        inc     codept
        loop    move_abc_widths
move_widths_exit:
        ret
get_some_widths ENDP

page

;---------------------------Public-Routine------------------------------;
; get_some_dbcs_widths
;
; Copies widths from the font to a POINTL struct setting y to 0 (width,0).
;
; Entry:
;       ecx number of characters we should get
;       esi long pointer to font
;       edi long pointer to array of DBCS font indexes
;             (will be replaced with points)
; Returns:
;       edi long pointer to array of points
; Error returns:
;       nothing
; Registers Destroyed:
;  EAX,EBX,ECX,EDX,EDI
;
; History:
;  30-Jun-1992 -by- Hide Muta [jl25345@ymtvm3]
; Modified for 32 bit model.
;  29-Nov-1990 -by- Soh Ohta [jl09057@ymtvm3]
; Created from get_some_widths.
;-----------------------------------------------------------------------;

get_some_dbcs_widths PROC SYSCALL uses ESI

; is this an a,b,c font?

        movzx   eax,[esi].ff_fdDefinitions.fdh_fsChardef
        add     esi,ff_fdDefinitions + size FONTDEFINITIONHEADER
        cmp     eax,FONTDEFCHAR3
        je      gsdw_move_abc_widths

gsdw_move_the_char_widths:
        mov     eax,[edi]               ; get DBCS font index
        mov     ebx,eax                 ; each record is 3 words mul by 6
        shl     ebx,2
        add     eax,eax
        add     ebx,eax
gsdw_move_add:
        movzx   eax,[esi][ebx].abc_a_space ; get the width from the font
        stosd
        loop    gsdw_move_the_char_widths
        jmp     gsdw_move_widths_exit

; handle the abc spacing case

gsdw_move_abc_widths:
        mov     edx,[edi]               ; get DBCS font index
        mov     ebx,edx                 ; abc record is 5 words so mul by 10
        shl     ebx,3
        add     ebx,edx
        add     ebx,edx
gsdw_abc_add:
        movzx   eax,[esi][ebx].abc_a_space ; get a
        add     ax,[esi][ebx].abc_b_space ; add in b
        add     ax,[esi][ebx].abc_c_space ; add in c
        stosd
        loop    gsdw_move_abc_widths

gsdw_move_widths_exit:
        ret
get_some_dbcs_widths ENDP

page

;---------------------------Public-Routine------------------------------;
; get_dbcs_font_indexes
;
; Get list of font index into lpWidth.
;
; Entry:
;   ESI = fontseg
;   EBP = QueryWidthTable frame
; Returns:
;       nothing
; Error returns:
;       nothing
; Registers Destroyed:
;  EAX,EBX,ECX,EDI
;
; History:
;  30-Jun-1992 -by- Hide Muta [jl25345@ymtvm3]
; Modified for 32 bit model.
;  14-May-1991 -by- Soh Ohta [jl09057@ymtvm3]
; Created.
;-----------------------------------------------------------------------;

 OPTION PROLOGUE:NONE
 OPTION EPILOGUE:NONE

get_dbcs_font_indexes PROC SYSCALL,
                hdc             :DWORD,
                firstChar       :DWORD,
                N               :DWORD,
                lpWidths        :DWORD,
                hddc            :DWORD,
                FunN            :DWORD
        LOCAL   npts            :DWORD,
                codepageoffset  :DWORD,
                lcodepage       :DWORD

        cld

; fill latter half of width table with DBCS code points.

        mov     ecx,N                   ; string length in bytes
 lea edi,ArrayConvTable2
 mov ax,firstChar.lo
@@:     stosd
        add     ah,1
        adc     al,0
        loop    @b

; translate DBCS code points to a list of font index.

        mov     ecx,N
 shl ecx,1   ; string length in bytes
 lea edi,ArrayConvTable2
        mov     eax,lcodepage           ; logical code page to be used
        INVOKE  DbcsMapCharGlyph        ; translate to glyph index

        mov     ecx,N
 lea edi,ArrayConvTable2
        neg     ecx                      ; make a extent call
        INVOKE  DbcsValidateFontSeg      ; EDI --> list of font index

 push esi
        mov     ecx,N
 lea esi,ArrayConvTable2
 mov edi,lpWidths
 rep movsd
 pop esi

        ret
get_dbcs_font_indexes ENDP

 OPTION PROLOGUE:PrologueDef
 OPTION EPILOGUE:EpilogueDef

        end
