Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

686 lines
27 KiB

page ,132
;*****************************Module*Header*******************************\
; Module Name: cache.asm
;
;
; Created: 9-Dec-1992
; Author: Paul Butzi
;
; Copyright (c) 1990-1999 Microsoft Corporation
;
;*************************************************************************/
; Note: This module would be more efficient with Frame Pointer Omission
; (FPO), whereby the stack is addressed off ESP rather than EBP, so we
; could stop pushing and popping EBP. However, the ASM macros currently
; don't support FPO.
;*************************************************************************/
.386
.model small,c
assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
assume fs:nothing,gs:nothing
.xlist
include callconv.inc
include gdii386.inc
.list
.code
EXTRNP xprunFindRunRFONTOBJ,2
EXTRNP xpgdDefault,1
EXTRNP xInsertMetricsRFONTOBJ,3
EXTRNP xInsertMetricsPlusRFONTOBJ,3
EXTRNP xInsertGlyphbitsRFONTOBJ,3
ifdef FE_SB
EXTRNP xwpgdGetLinkMetricsRFONTOBJ,2
EXTRNP xwpgdGetLinkMetricsPlusRFONTOBJ,3
endif
FAST_WCHAR_BASE equ 20h ; Most ANSI fonts have a base of 32
;******************************Public*Routine******************************\
;
; BOOL RFONTOBJ::bGetGlyphMetrics (
; COUNT c,
; GLYPHPOS *pgp,
; WCHAR *pwc
; );
;
; Translate wchars into an array of GLYPHPOS structures, filling in
; the pointer to GLYPHDATA field. Only the metrics are assured to be
; valid; no attempt is made to ensure that the glyph data itself is
; present in the cache before the return to the caller.
;
; This routine is to be used primarily by GetTextExtent and GetCharWidths,
; which have no need for anything except metrics.
;
; A zero return means that we failed to insert the metrics due to some
; hard error, most likely a failure to commit memory in the glyph
; insertion routine.
;
; History:
; 21-Dec-92 -by- Michael Abrash
; Fixed bug in detecting run inclusion
; 9-Dec-92 -by- Paul Butzi
; Wrote it.
;**************************************************************************/
cPublicProc xGetGlyphMetrics,4,< \
uses ebx esi edi, \
pThis: ptr dword, \
c_: dword, \
pgp: ptr dword, \
pwc: dword >
mov eax, pThis ; (eax) = ptr to RFONTOBJ
mov eax, [eax].prfnt ; (eax) = ptr to RFONT
mov esi, pwc ; pointer to wchar data
;*486 pipelining
mov eax, [eax].wcgp ; (eax) = ptr to wcgp
mov edi, pgp ; pointer to glyphpos array to fill
;*486 pipelining
lea ebx, [eax].agprun ; (ebx) = ptr to first wcgp run
;*486 pipelining
mov ecx, [ebx].wcLow ; index of start of run
mov edx, [ebx].cGlyphs ; # of glyphs in run
mov ebx, [ebx].apgd ; pointer to run's pointers to cached
; glyphdata
push ebp
mov ebp,c_ ; we'll use EBP for the glyph count
; ***stack frame no longer available***
;
; Invariants:
; (esi) = ptr to wchar
; (edi) = ptr to pgp
; (ebx) = ptr to base of current run
; (ecx) = wcLow of current run
; (edx) = cGlyphs of current run
; (ebp) = count of glyphs remaining
loop_top:
sub eax, eax
mov ax, [esi] ; (eax) = wchar, zero extended
sub eax, ecx ; get index relative to current run base
cmp eax, edx ; is wchar in this run?
jae short find_run ; wrong run, better go get right one
run_found:
mov eax, [ebx+4*eax] ; (ecx) = ptr to glyphdata
;
; Invariants:
; (esi, edi, ebx, ecx, edx) as above at loop top
; (eax) = ptr to glyphdata
;
default_found:
and eax, eax ; is cached glyphdata there?
jz short get_glyph ; no glyphdata, better go get one
;
; Here, we are assured that the glyphdata is present in the cache
;
glyph_found:
mov [edi].gp_pgdf, eax ; set ptr to glyphdata in glyphpos
mov eax, [eax].gd_hg
mov [edi].gp_hg, eax ; set hg in glyphpos
add edi, SIZE_GLYPHPOS ; next glyphpos to fill in
add esi, 2 ; next wchar to look up
dec ebp ; any more glyphs?
jnz loop_top
pop ebp ; ***stack frame available***
mov eax, 1 ; success
stdRET xGetGlyphMetrics
;=======================================================================
; We got here because the current run does not contain the wchar we're
; interested in. Note that the following invariants must hold when
; we re-enter the loop (starred items must hold on entry, as well):
; (esi) = ptr to wchar*
; (edi) = ptr to pgp*
; (ebx) = ptr to apgd of new run
; (ecx) = wcLow of new run
; (edx) = cGlyphs of new run
; (eax) = ptr to glyphdata
; (ebp) = count of glyphs remaining*
;=======================================================================
align 4
find_run:
push ebp ; preserve count of remaining glpyhs
mov ebp,[esp+4] ; ***stack frame available***
; *****************************************
; * Note that the approach here is to get *
; * EBP off the stack, where it was *
; * pushed, by addressing off ESP. EBP *
; * remains pushed, so we don't need to *
; * re-push it when we're done. *
; * XCHGing EBP with the top of the stack *
; * would be cleaner, but XCHG locks the *
; * bus. *
; * This trick is repeated several times *
; * below. *
; *****************************************
sub eax, eax
mov ax, [esi] ; (eax) = current wchar
mov ebx, pThis
stdcall xprunFindRunRFONTOBJ, <ebx, eax> ; find the wchar's run
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
mov ecx, [eax].wcLow ; index of start of new run
mov edx, [eax].cGlyphs ; # of glyphs in new run
mov ebx, [eax].apgd ; pointer to new run's pointers to
; cached glyphdata
sub eax, eax
mov ax, [esi] ; (eax) = current wchar
sub eax, ecx ; get index relative to new run base
cmp eax, edx ; is wchar in this run?
jb run_found ; yes, run with it
; not in any run; use default character
push ebp ; preserve count of remaining glyphs
mov ebp,[esp+4] ; ***stack frame available***
ifdef FE_SB ; call off to linked font handler
push ebx
push ecx
push edx
mov eax, pThis ; (eax) = pointer to RFONTOBJ
sub ebx,ebx ; (ebx) = 0
mov bx, [esi] ; (ebx) = current wchar
stdcall xwpgdGetLinkMetricsRFONTOBJ,<eax,ebx>
pop edx
pop ecx
pop ebx
else
mov eax, pThis
push ecx
push edx
stdcall xpgdDefault, <eax> ; eax = ptr to default character
pop edx
pop ecx
endif
pop ebp ; <ebp> = glyph count
jmp default_found ; go with the default character
;=======================================================================
; We got here because the glyph pointer in the wcgp run was null, meaning
; we don't yet have the metrics for this glyph. Note that the following
; invariants must be true on exit (starred items must hold on entry, as
; well):
; (esi) = ptr to wchar*
; (edi) = ptr to pgp*
; (ebx) = ptr to apgd of new run*
; (ecx) = wcLow of new run*
; (edx) = cGlyphs of new run*
; (eax) = ptr to glyphdata
; (ebp) = count of glyphs remaining*
;=======================================================================
align 4
get_glyph:
push ebp ; preserve count of remaining glpyhs
mov ebp,[esp+4] ; ***stack frame available***
push ebx
push edx
push ecx
sub eax, eax
mov ax, [esi] ; (eax) = wchar
mov edx, eax ; set aside wchar
sub eax, ecx ; (eax) = index into run
lea ebx, [ebx+eax*4] ; (ebx) = ptr to entry
mov ecx,pThis
stdcall xInsertMetricsRFONTOBJ, <ecx, ebx, edx>
pop ecx
pop edx
and eax, eax ; were we able to get the glyph metrics?
jz short failed ; no
mov eax, [ebx] ; get ptr to glyphdata from cache entry
pop ebx
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
jmp glyph_found
failed:
pop ebx
pop eax ; clear glyph count from stack
pop eax ; clear pushed stack frame pointer from stack
sub eax, eax ; failure
stdRET xGetGlyphMetrics
stdENDP xGetGlyphMetrics
;******************************Public*Routine******************************\
;
; BOOL RFONTOBJ::bGetGlyphMetricsPlus (
; COUNT c,
; GLYPHPOS *pgp,
; WCHAR *pwc,
; BOOL *pbAccel
; );
;
; Translate wchars into an array of GLYPHPOS structures, filling in
; the pointer to GLYPHDATA field. Although only the metrics are assured to be
; valid, an attempt is made to ensure that the glyph data itself is
; present in the cache before the return to the caller. Failure in this
; attempt is indicated by clearing the flag *pbAccel. This allows the
; text code to tell the device driver that the STROBJ_bEnum callback is
; not needed.
;
; This routine is to be used primarily by TextOut and its kin.
;
; A zero return means that we failed to insert the metrics due to some
; hard error, most likely a failure to commit memory in the glyph
; insertion routine.
;
; This is a replacement for the C++ version in cache.cxx
;
; History:
; 21-Dec-92 -by- Michael Abrash
; Fixed bug in detecting run inclusion
; 9-Dec-92 -by- Paul Butzi
; Wrote it.
;**************************************************************************/
cPublicProc xGetGlyphMetricsPlus,5,< \
uses ebx esi edi, \
pThis: ptr dword, \
c_: dword, \
pgp: ptr dword, \
pwc: dword, \
pbAccel: ptr dword >
local pbacceltmp : dword ;1 if all glyph bits have been gotten
; so far, 0 if not
mov eax, pThis ; (eax) = ptr to RFONTOBJ
mov pbacceltmp,1 ; set bAccel to true (all glyph bits
; realized so far)
;*486 pipelining
mov eax, [eax].prfnt ; (eax) = ptr to RFONT
mov esi, pwc ; pointer to wchar data
;*486 pipelining
mov eax, [eax].wcgp ; (eax) = ptr to wcgp
mov edi, pgp ; pointer to glyphpos array to fill
;*486 pipelining
lea ebx, [eax].agprun ; (ebx) = ptr to first wcgp run
;*486 pipelining
push ebp ;*486 pipelining
mov ecx, [ebx].wcLow ; index of start of run
mov edx, [ebx].cGlyphs ; # of glyphs in run
mov ebx, [ebx].apgd ; pointer to run's pointers to cached
; glyphdata
mov ebp,c_ ; we'll use EBP for the glyph count
; ***stack frame no longer available***
;--------------------------------------------------------------------------
; Fast two-glyphs-at-a-time Pentium pipe-lined loop
;
; The philosophy of this loop is that for the vast majority of the time,
; all the glyphs will be in the proper range, have cached glyphdata, and
; have cached glyphbits -- and it takes advantage of that to better make
; use of both Pentium pipes by doing two glyphs at once. If one of those
; conditions fail, it converts to the single-glyph-at-a-time loop when
; that happens.
;
; Invariants:
; (esi) = ptr to 1st wchar
; (edi) = ptr to pgp
; (ecx) = ptr to 2nd wchar
; (ecx) = wcLow of current run
; (edx) = cGlyphs of current run
; (ebp) = count of glyphs remaining
; [esp] = wcLow of current run
cmp ecx, FAST_WCHAR_BASE ; fast loop handles wcLow values only
jne gmp_slow_loop_top ; of 32
dec ebp ; pre-decrement count
jz gmp_slow_loop_top ; only one character. it's okay to
; pop this through to gmp_slow_loop_top
; with a zero count -- it's effectively
; the same as a one count
push ecx ; wcLow is now at [esp]
gmp_fast_loop_top:
mov eax, [esi] ; 1U (eax) = first two glyphs
add edi, 2*SIZE_GLYPHPOS ; 1V each iteration does two glyphpos's.
; we do this now to eat up a free V
; pipe instruction
mov ecx, eax ; 1U
add esi, 4 ; 1V each iteration does two wchars.
; we do this now to eat up a free V
; pipe instruction
shr ecx, 16 ; 1U (ecx) = 2nd wchar, zero extended
and eax, 0ffffh ; 1V (eax) = 1st wchar, zero extended
sub eax, FAST_WCHAR_BASE ; 1U get index relative to current base
sub ecx, FAST_WCHAR_BASE ; 1V get index relative to current base
cmp eax, edx ; 1U is 1st wchar in this run?
jae gmp_restart_in_slow_loop; 1V wrong run, exit fast loop
cmp ecx, edx ; 1U is 2nd wchar in this run?
jae gmp_restart_in_slow_loop; 1V wrong run, exit fast loop
mov eax, [ebx+4*eax] ; 2U (eax) = ptr to 1st glyphdata
mov ecx, [ebx+4*ecx] ; 2V (ecx) = ptr to 2nd glyphdata
; (could be 3V if in same cache
; bank)
test eax, eax ; 1U is 1st cached glyphdata there?
jz gmp_restart_in_slow_loop; 1V no glyphdata, exit fast loop
test ecx, ecx ; 1U is 2nd cached glyphdata there?
jz gmp_restart_in_slow_loop; 1V no glyphdata, exit fast loop
cmp dword ptr [eax].gd_gdf, 0 ; 2U are 1st glyph bits in cache?
je gmp_restart_in_slow_loop ; 1V no, go get them
cmp dword ptr [ecx].gd_gdf, 0 ; 2U are 2nd glyph bits in cache?
je gmp_restart_in_slow_loop ; 1V no, go get them
mov [edi-2*SIZE_GLYPHPOS].gp_pgdf, eax
; 1U set ptr to glyphdata in glyphpos
mov eax, [eax].gd_hg ; 1V read 1st glyph handle
mov [edi-1*SIZE_GLYPHPOS].gp_pgdf, ecx
; 1U set ptr to glyphdata in glyphpos
mov ecx, [ecx].gd_hg ; 1V read 2nd glyph handle
mov [edi-2*SIZE_GLYPHPOS].gp_hg,eax ; 1U set handle in glyphpos
mov [edi-1*SIZE_GLYPHPOS].gp_hg,ecx ; 1V set handle in glyphpos
sub ebp, 2 ; 1U each iteration does two glyphs
jg gmp_fast_loop_top ; 1V more loops to do
pop ecx ; account for pushed wcLow
jz gmp_slow_loop_top ; odd number of glyphs, handle last one
pop ebp ; ***stack frame available***
mov ebx,pbaccel ; where we'll store whether all glyph
; bits found
mov eax, 1 ; success
mov [ebx], 1 ; success
stdRET xGetGlyphMetricsPlus
;--------------------------------------------------------------------------
; Not-so-fast one-glyph-at-a-time loop
;
; Invariants:
; (esi) = ptr to wchar
; (edi) = ptr to pgp
; (ebx) = ptr to base of current run
; (ecx) = wcLow of current run
; (edx) = cGlyphs of current run
; (ebp) = count of glyphs remaining
gmp_restart_in_slow_loop:
pop ecx ; (ecx) = wcLow of current run
inc ebp ; account for fast-loop preadjustments
sub edi, 2*SIZE_GLYPHPOS
sub esi, 4
gmp_slow_loop_top:
sub eax, eax
mov ax, [esi] ; (eax) = wchar, zero extended
sub eax, ecx ; get index relative to current run base
cmp eax, edx ; is wchar in this run?
jae short gmp_find_run ; wrong run, better go get right one
gmp_run_found:
mov eax, [ebx+4*eax] ; (ecx) = ptr to glyphdata
;
; Invariants:
; (esi, edi, ebx, ecx, edx) as above at loop top
; (eax) = ptr to glyphdata
;
gmp_default_found:
and eax, eax ; is cached glyphdata there?
jz gmp_get_glyph ; no glyphdata, better go get one
;
; Here, we are assured that the glyphdata is present in the cache
;
gmp_glyph_found:
cmp dword ptr [eax].gd_gdf, 0 ; are the glyph bits in the cache?
jz gmp_get_bits ; no, go get them
;
; Here, we have tried to get the glyphbits in the cache
;
gmp_got_bits:
mov [edi].gp_pgdf, eax ; set ptr to glyphdata in glyphpos
mov eax, [eax].gd_hg
mov [edi].gp_hg, eax ; set hg in glyphpos
add edi, SIZE_GLYPHPOS ; next glyphpos to fill in
add esi, 2 ; next wchar to look up
dec ebp ; any more glyphs?
jg gmp_slow_loop_top ; must be 'greater than' check
pop ebp ; ***stack frame available***
mov ebx,pbaccel ; where we'll store whether all glyph bits found
mov eax,pbacceltmp ; 0 if not all found, 1 if all found
mov [ebx],eax ; return whether we found all glyph bits or not
mov eax, 1 ; success
stdRET xGetGlyphMetricsPlus
;=======================================================================
; We got here because the current run does not contain the wchar we're
; interested in. Note that the following invariants must hold when
; we re-enter the loop (starred items must hold on entry, as well):
; (esi) = ptr to wchar*
; (edi) = ptr to pgp*
; (ebx) = ptr to apgd of new run
; (ecx) = wcLow of new run
; (edx) = cGlyphs of new run
; (eax) = ptr to glyphdata
; (ebp) = count of glyphs remaining*
;=======================================================================
align 4
gmp_find_run:
push ebp ; preserve count of remaining glpyhs
mov ebp,[esp+4] ; ***stack frame available***
sub eax, eax
mov ax, [esi] ; (eax) = current wchar
mov ebx, pThis
stdcall xprunFindRunRFONTOBJ, <ebx, eax>
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
mov ecx, [eax].wcLow ; index of start of new run
mov edx, [eax].cGlyphs ; # of glyphs in new run
mov ebx, [eax].apgd ; pointer to new run's pointers to
; cached glyphdata
sub eax, eax
mov ax, [esi] ; (eax) = current wchar
sub eax, ecx ; get index relative to new run base
cmp eax, edx ; is wchar in this run?
jb gmp_run_found ; yes, run with it
; not in any run; use default character
push ebp ; preserve count of remaining glyphs
mov ebp,[esp+4] ; ***stack frame available***
ifdef FE_SB
push ebx
push ecx
push edx
mov eax, pThis ; (eax) = pointer to RFONTOBJ
lea ebx, pbacceltmp ; (ebx) = pointer to pbacceltmp
; (esi) = pointer to current wchar
stdcall xwpgdGetLinkMetricsPlusRFONTOBJ,<eax,esi,ebx>
pop edx
pop ecx
pop ebx ; (eax) is now proper wpgd
else
mov eax,pThis
push ecx
push edx
stdcall xpgdDefault, <eax> ; eax = ptr to default character
pop edx
pop ecx
endif
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
jmp gmp_default_found ; go with the default character
;=======================================================================
; We got here because the glyph pointer in the wcgp run was null, meaning
; we don't yet have the metrics for this glyph. Note that the following
; invariants must be true on exit (starred items must hold on entry, as
; well):
; (esi) = ptr to wchar*
; (edi) = ptr to pgp*
; (ebx) = ptr to apgd of new run*
; (ecx) = wcLow of new run*
; (edx) = cGlyphs of new run*
; (eax) = ptr to glyphdata
; (ebp) = count of glyphs remaining*
;=======================================================================
align 4
gmp_get_glyph:
push ebp ; preserve count of remaining glpyhs
mov ebp,[esp+4] ; ***stack frame available***
push ebx
push edx
push ecx
sub eax, eax
mov ax, [esi] ; (eax) = wchar
mov edx, eax ; set aside wchar
sub eax, ecx ; (eax) = index into run
lea ebx, [ebx+4*eax] ; (ebx) = ptr to entry
mov ecx,pThis
stdcall xInsertMetricsPlusRFONTOBJ, <ecx, ebx, edx>
pop ecx
pop edx
and eax, eax ; were we able to get the glyph metrics?
jz short gmp_failed ; no
mov eax, [ebx] ; get ptr to glyphdata from it
pop ebx
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
jmp gmp_glyph_found
gmp_failed:
pop ebx
pop eax ; clear glyph count from stack
pop eax ; clear pushed stack frame pointer from stack
sub eax, eax ;failure
stdRET xGetGlyphMetricsPlus
;=======================================================================
; We get here if we need to try to load the bits for the glyph we're
; interested in (because the bits havene't been realized yet). We only
; even bother to try if all bits have successfully been realized so far,
; because it's only useful to realize glyphs if we can get all of them.
; Note that the following invariants must be true on both entry and exit.
; (esi) = ptr to wchar
; (edi) = ptr to pgp
; (ebx) = ptr to apgd of new run
; (ecx) = wcLow of new run
; (edx) = cGlyphs of new run
; (eax) = ptr to glyphdata
; (ebp) = count of glyphs remaining
;=======================================================================
align 4
gmp_get_bits:
push ebp ; preserve count of remaining glpyhs
mov ebp,[esp+4] ; ***stack frame available***
cmp pbacceltmp,0 ;if we already failed to get glyph bits
je short got_the_bits_done ; once, no point in trying again
push ecx
mov ecx, pThis
push edx ;*486 pipelining
mov edx, [ecx].prfnt
push eax ;*486 pipelining
cmp dword ptr [edx].ulContent, FO_HGLYPHS
je short got_the_bits
sub edx,edx
cmp pwc,esi
sbb edx,-1 ; EDX == TRUE if first wc, FALSE else
stdcall xInsertGlyphbitsRFONTOBJ, <ecx, eax, edx> ;try to get the bits
and eax, eax ; did we succeed in getting the bits?
jnz short got_the_bits ; yes, we got the bits
mov pbacceltmp, eax ; didn't get the glyph (note: EAX is zero)
got_the_bits:
pop eax
pop edx
pop ecx
got_the_bits_done:
pop ebp ; <ebp> = glyph count
; ***stack frame no longer available***
jmp gmp_got_bits
stdENDP xGetGlyphMetricsPlus
end