*** dix/dixfonts.c	1999/12/26 01:57:02	1.1
--- dix/dixfonts.c	1999/12/26 16:25:10
***************
*** 871,876 ****
--- 871,1096 ----
      return Success;
  }
  
+ // Some stupid X-application such as Netscape repeatedly calls
+ // StartListFontsWithInfo(client 137651332, pattern *-iso8859-1, max_names 10
0).
+ // This opens large amount of font files and recalcurate font metrics
+ // repeatedly. Each call takes more than 10 seconds. So we memorise several
+ // results ( > 1024 ) in hash table. S. Kono
+ 
+ int Memorize_FontWithInfo = 1;
+ #define MEMORIZE_FONTWITHINFO_SIZE 1024 
+ 
+ #ifdef  MEMORIZE_FONTWITHINFO_DEBUG 
+ #define MF_DEBUG(x) x
+ #else
+ #define MF_DEBUG(x) 
+ #endif
+ 
+ static struct FontWithInfoMemoryStart {
+     int patlen;
+     char *pattern;
+     FontPathElementPtr fpe;
+     int result;
+     struct FontWithInfoMemoryNext {
+ 	int         result;
+ 	char        *name;
+ 	int         namelen;
+ 	int         numFonts;
+ 	FontInfoRec *pFontInfo;
+ 	struct FontWithInfoMemoryNext *next;
+     } *next,**last;
+ } *FontWithInfoMemory[MEMORIZE_FONTWITHINFO_SIZE];
+ 
+ struct FontWithInfoMemoryStart *
+ searchFontWithInfoCache(pattern,patlen,fpe) 
+     char *pattern;
+     int patlen;
+     FontPathElementPtr fpe;
+ {
+     char *p;
+     unsigned int hash;
+     struct FontWithInfoMemoryStart *f;
+     int i;
+ 
+     // compute hash
+     for(hash = 0,p = pattern,i=0;*p && i<=patlen;  hash = (hash*7) ^ *p++);
+     for(p = fpe->name,i=0;*p && i<=fpe->name_length;  hash = (hash*7) ^ *p++)
;
+     hash %= MEMORIZE_FONTWITHINFO_SIZE;
+     if (f=FontWithInfoMemory[hash]) {
+ 	struct FontWithInfoMemoryNext *n;
+ 	if (f->pattern && f->patlen==patlen
+ 		&& strncmp(pattern,f->pattern,patlen)==0) {
+ 	    if (strncmp(f->fpe->name,fpe->name,f->fpe->name_length)==0) {
+ 		return f;
+ 	    }
+ 	}
+ 	// Wrong entry. Free this and reuse it.
+ 	if(--f->fpe->refcount==0) {
+ 	    if(f->fpe->private)
+ 		xfree(f->fpe->private);
+ 	    xfree(f->fpe);
+ 	}
+ 	for(n = f->next; n; n=n->next) {
+ 	    if(n->name)	xfree(n->name);
+ 	    n->name = 0;
+ 	    if (n->result==Successful) {
+ 		if (n->pFontInfo) {
+ 		    if(n->pFontInfo->props) xfree(n->pFontInfo->props);
+ 		    if(n->pFontInfo->isStringProp) xfree(n->pFontInfo->isString
Prop);
+ 		}
+ 	    }
+ 	    if (n->pFontInfo) xfree(n->pFontInfo);
+ 	    n->pFontInfo=0;
+ 	    // we never free struct FontWithInfoMemoryNext 
+ 	}
+     } else {
+ MF_DEBUG(fprintf(stderr,"FontWithInfoCache(pattern %s) new %x\n",pattern,f));
 
+ 	// allocate new cache
+ 	f = FontWithInfoMemory[hash] = (struct FontWithInfoMemoryStart *)
+ 	    xalloc(sizeof(struct FontWithInfoMemoryStart));
+ 	if(!f) return f;
+ 	f->pattern = 0;
+     }
+     if(f->pattern) {  // replace pattern
+ 	xfree(f->pattern);
+ 	f->pattern = 0;
+     }
+     f->pattern = (char *)xalloc(patlen);
+     f->patlen = patlen;
+     if(!f->pattern) return 0;
+     strncpy(f->pattern,pattern,patlen);
+     f->next=0;
+     f->last = &f->next;
+     f->fpe=fpe;
+     fpe->refcount++;
+     return f;
+ }
+ 
+ static int
+ lookupStartFontWithInfoCache(client,fpe, c)
+     ClientPtr   client;
+     FontPathElementPtr fpe;
+     LFWIclosurePtr c;
+ {
+     int err;
+     struct FontWithInfoMemoryStart *f;
+ 
+     f = searchFontWithInfoCache(c->current.pattern,c->current.patlen,fpe);
+     if (!f) return BadAlloc;
+     if (f->next && f->last==0) {   // Found completed entry
+ 	c->current.private = (pointer)f->next;
+ 	return f->result;
+     }
+     err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
+ 	(client, fpe, c->current.pattern, c->current.patlen,
+ 	 c->current.max_names, &c->current.private);
+     f->result = err;
+     return err;
+ }
+ 
+ static int
+ lookupFontWithInfoCache(client,fpe, pname, pnamelen, ppFontInfo, pnumFonts, c
)
+     ClientPtr   client;
+     FontPathElementPtr fpe;
+     LFWIclosurePtr c;
+     char        **pname;
+     int         *pnamelen;
+     int         *pnumFonts;
+     FontInfoPtr *ppFontInfo;
+ {
+     int err;
+     struct FontWithInfoMemoryStart *f;
+     struct FontWithInfoMemoryNext *next;
+ 
+     f = searchFontWithInfoCache(c->current.pattern,c->current.patlen,fpe);
+     if (!f) goto badAlloc;
+     if (f->last==0) { // found complete entry
+ 	next = c->current.private;
+ 	if (!next) {
+ 	    if (f->pattern) f->pattern[0]=0; // invalidate this entry
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache(name %s) BadAlloc return %d 
%x\n",c->current.pattern,err,next)); 
+ 	    return BadAlloc;
+ 	}
+ 	err = next->result;
+ 	if (err==Successful || err==FontNameAlias) {
+ 	    *pname = next->name;
+ 	    *pnamelen = next->namelen;
+ 	    *ppFontInfo = next->pFontInfo;
+ 	    *pnumFonts = next->numFonts;
+ 	}
+ 	c->current.private = (pointer)next->next;
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache(name %s) return %d %x\n",c->
current.pattern,err,next)); 
+ 	return err;
+     }
+     err = (*fpe_functions[fpe->type].list_next_font_with_info)
+ 	(client, fpe, pname, pnamelen, ppFontInfo,
+ 	 pnumFonts, c->current.private);
+     // memorize it 
+     if (err==Successful || err==FontNameAlias || err==BadFontName) {
+ 	int i,j;
+ 	if (! *f->last) {
+ 	    if(! (next = *f->last = 
+ 		(struct FontWithInfoMemoryNext *)
+ 		xalloc(sizeof(struct FontWithInfoMemoryNext))))
+ 		goto badAlloc;
+ 	    next->next=0;
+ 	    next->name=0;
+ 	    next->pFontInfo = 0;
+ 	    f->last = &next->next;
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache new next %x\n",next)); 
+ 	} else {
+ 	    next = *f->last;
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache reuse next %x\n",next)); 
+ 	}
+ 	next->result = err;
+ 	if (err==FontNameAlias)  {
+ 	    if(! (next->pFontInfo = (FontInfoPtr)xalloc(strlen((char *)*ppFontI
nfo))))
+ 		goto badAlloc;
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache(alias) memorize %d %x\n",err
,next)); 
+ 	    strcpy((char *)next->pFontInfo,(char *)*ppFontInfo);
+ 	    if(! (next->name = (char *)xalloc(*pnamelen)))
+ 		goto badAlloc;
+ 	    strncpy(next->name,*pname,*pnamelen);
+ 	    next->namelen = *pnamelen;
+ 	    next->numFonts = *pnumFonts;
+ 	    return err;
+ 	} else if (err!=Successful) {
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache(Bad) memorize %d %x\n",err,n
ext)); 
+ 	    return err;
+ 	}
+ MF_DEBUG(fprintf(stderr,"lookupFontWithInfoCache(name %s) memorize %d %x\n",*
pname,err,next)); 
+ 	if(! (next->pFontInfo = (FontInfoRec *) xalloc(sizeof(FontInfoRec))))
+ 	    goto badAlloc;
+ 	next->pFontInfo->props = 0;
+ 	next->pFontInfo->isStringProp = 0;
+ 	if(! (next->name = (char *)xalloc(*pnamelen)))
+ 	    goto badAlloc;
+ 	strncpy(next->name,*pname,*pnamelen);
+ 	next->namelen = *pnamelen;
+ 	next->numFonts = *pnumFonts;
+ 	*next->pFontInfo = **ppFontInfo; // struct copy
+ 	if(j = (*ppFontInfo)->nprops) {
+ 	    if(!(next->pFontInfo->props = (FontPropPtr)xalloc(sizeof(FontPropRe
c)*j)))
+ 		goto badAlloc;
+ 	    for (i = 0; i < j; i++) {
+ 		next->pFontInfo->props[i].name = (*ppFontInfo)->props[i].name;
+ 		next->pFontInfo->props[i].value = (*ppFontInfo)->props[i].value
;
+ 	    }
+ 	}
+ 	if ((*ppFontInfo)->isStringProp) {
+ 	    if(! (next->pFontInfo->isStringProp = (char *) xalloc(j)))
+ 		goto badAlloc;
+ 	    strncpy(next->pFontInfo->isStringProp,(*ppFontInfo)->isStringProp,j
);
+ 	}
+     } 
+     return err;
+ badAlloc:
+     if (f && f->pattern)
+ 	f->pattern[0]=0; // Invalidate this entry, if it exists.
+     return BadAlloc;
+ }
+ 
+ 
  int
  doListFontsWithInfo(client, c)
      ClientPtr   client;
***************
*** 909,917 ****
  	err = Successful;
  	if (!c->current.list_started)
   	{
! 	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
! 		(client, fpe, c->current.pattern, c->current.patlen,
! 		 c->current.max_names, &c->current.private);
  	    if (err == Suspended)
   	    {
  		if (!c->slept)
--- 1129,1141 ----
  	err = Successful;
  	if (!c->current.list_started)
   	{
! 	    if (Memorize_FontWithInfo) {
! 		err = lookupStartFontWithInfoCache(client, fpe, c);
! 	    } else {
! 		err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
! 		    (client, fpe, c->current.pattern, c->current.patlen,
! 		     c->current.max_names, &c->current.private);
! 	    }
  	    if (err == Suspended)
   	    {
  		if (!c->slept)
***************
*** 928,936 ****
   	{
  	    name = 0;
  	    pFontInfo = &fontInfo;
! 	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
! 		(client, fpe, &name, &namelen, &pFontInfo,
! 		 &numFonts, c->current.private);
  	    if (err == Suspended)
   	    {
  		if (!c->slept)
--- 1152,1166 ----
   	{
  	    name = 0;
  	    pFontInfo = &fontInfo;
! 	    if (Memorize_FontWithInfo) {
! 		err = lookupFontWithInfoCache(
! 		    client, fpe, &name, &namelen, &pFontInfo,
! 		    &numFonts, c);
! 	    } else {
! 		err = (*fpe_functions[fpe->type].list_next_font_with_info)
! 		    (client, fpe, &name, &namelen, &pFontInfo,
! 		     &numFonts, c->current.private);
! 	    }
  	    if (err == Suspended)
   	    {
  		if (!c->slept)
***************
*** 965,973 ****
  
  	    	tmpname = 0;
  	    	tmpFontInfo = &fontInfo;
! 	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
! 		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
! 		     &numFonts, c->current.private);
  		if (--aliascount <= 0)
  		{
  		    err = BadFontName;
--- 1195,1209 ----
  
  	    	tmpname = 0;
  	    	tmpFontInfo = &fontInfo;
! 		if (Memorize_FontWithInfo) {
! 		    (void) lookupFontWithInfoCache(
! 			client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
! 			&numFonts, c);
! 		} else {
! 		    (void) (*fpe_functions[fpe->type].list_next_font_with_info)
! 			(client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
! 			 &numFonts, c->current.private);
! 		}
  		if (--aliascount <= 0)
  		{
  		    err = BadFontName;
***************
*** 998,1003 ****
--- 1234,1247 ----
  	else if (err == BadFontName)
   	{
  	  ContBadFontName: ;
+ 	    if (Memorize_FontWithInfo) {
+ 		struct FontWithInfoMemoryStart *f;
+ 		f = searchFontWithInfoCache(c->current.pattern,c->current.patle
n,fpe);
+ MF_DEBUG(fprintf(stderr,"doListFontsWithInfo(pattern %s) current fpe end %x\n
",c->current.pattern,f)); 
+ 		if (f) 
+ 		    f->last = 0;
+ 		// else BadAlloc, but this cannot happen
+ 	    }
  	    c->current.list_started = FALSE;
  	    c->current.current_fpe++;
  	    err = Successful;
***************
*** 1072,1077 ****
--- 1316,1331 ----
  	}
      }
  finish:
+     // cache entry completed
+     if (Memorize_FontWithInfo) {
+ 	struct FontWithInfoMemoryStart *f;
+ 	f = searchFontWithInfoCache(c->current.pattern,c->current.patlen,fpe);
+ MF_DEBUG(fprintf(stderr,"doListFontsWithInfo(pattern %s) complete %x\n",c->cu
rrent.pattern,f)); 
+ 	if (f) 
+ 	    f->last = 0;
+ 	// else BadAlloc, but this cannot happen
+     }
+ 
      length = sizeof(xListFontsWithInfoReply);
      bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
      finalReply.type = X_Reply;
