[Fontconfig] how to use multiple fonts?

Federic Zhang Federic.Zhang at Sun.COM
Fri Mar 14 21:45:23 EST 2003


Keith Packard wrote:

> Around 11 o'clock on Mar 5, Federic Zhang wrote:
>
> > Thanks for this information.  I will refer to the corresponding implemention
> > in Pango, using low-level FcFontSort is too complicated at least for me.
>
> Yes, it is rather complicated.  Perhaps your experience can serve as a
> guide for a higher level interface that could be integrated into Xft.
>

I finished one by following implementation within Pango.

The attached APIs can be used as reference to implement  the new API
with multiple fonts, it would be great if they can be integreated into Xft.
They can be used as like:

        XftText *text = XftCreateText(dpy, scr, pattern, str, count_chars,
StringUtf8);
        XftDrawText(draw, color, text, x, y);

Of course, its performance is one outstanding issue.

-federic

-------------- next part --------------
#include <glib.h>
#include <fontconfig/fontconfig.h>
#include <Xfttext.h>

typedef struct _XftPatternSet {
   int num_patterns;
   FcPattern **patterns;
} XftPatternSet;

typedef struct _CharProp {
   int pattern_index; /* index of "patterns" */ 
   int count_chars;   /* number of characters sharing the same pattern */
} CharProp;

static void
XftFreePatternSet(XftPatternSet *set)
{
   int n;
   
   for (n=0; n < set->num_patterns; ++n)
       FcPatternDestroy(set->patterns[n]);
     
    g_free(set->patterns);
    g_free(set);
}

static XftPatternSet *
XftCreatePatternSet(FcPattern *pattern)
{
   XftPatternSet *set;
   FcFontSet     *font_patterns;
   int f;
   
   font_patterns = FcFontSort(NULL, pattern, FcTrue, 0, NULL);
   if (!font_patterns) return NULL;
 
   set = g_new0(XftPatternSet, 1);
   set->patterns = g_new0(FcPattern *, font_patterns->nfont);
   set->num_patterns = font_patterns->nfont;

   for (f=0; f < font_patterns->nfont; f++)
	set->patterns[f] = FcFontRenderPrepare(NULL, pattern, font_patterns->fonts[f]);
    
   FcFontSetDestroy(font_patterns);

   return set;
}
   
static int
getFontIdx(FcChar32 ucs4, XftPatternSet *set)
{
   int n;
   
   for (n=0; n < set->num_patterns; ++n)
     {
       FcCharSet *charset;
       FcPattern *pattern = set->patterns[n];
	
       if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
         return -1;

       if (FcCharSetHasChar(charset, ucs4)) return n;
     }
	
   return -1;
}

static CharProp *
getCharProp(XftPatternSet *set, void *v, int count_chars, XftTextEncoding encoding)
{
    CharProp *charprop;
    int i, position,prev_index;
   
    charprop = g_new0(CharProp, count_chars);
    for (i = 0; i < count_chars; ++i)
     {
       gunichar ucs4;
       
       switch (encoding)
	  {
	  case String8:
	     {
		char *p = (char *)v;
		ucs4 = (FcChar32)*p;
		v = (void *)(p+1);
	     }	     
	     break;
	  case String16:
	     {
		FcChar16 *p = (FcChar16 *)v;
		ucs4 = (FcChar32)*p;
		v = (void *)(p+1);
	     }
	     break;
	  case String32:
	     {
		FcChar32 *p = (FcChar32 *)v;
		ucs4 = *p;
		v = (void *)(p+1);
	     }	     
	     break;
	  case StringUtf8:
	     {
	        char *p = (char *)v;
	        ucs4 = g_utf8_get_char(p);
	        v = (void *)g_utf8_next_char(p);
	      }
	     break;
	  case StringUtf16:
	     // not implemented yet
	     break;
	  }
	
       charprop[i].pattern_index = getFontIdx(ucs4, set);
     }
   
    position = 0;
    prev_index = charprop[0].pattern_index;
    for(i=1; i < count_chars; ++i)
     {
	if (charprop[i].pattern_index != prev_index)
	  {
	     charprop[position].count_chars = i - position;
	     prev_index = charprop[i].pattern_index;
	     position = i;
	  }	
     }   
   charprop[position].count_chars = i - position;
   
   return charprop;
}

XftText *
XftCreateText(Display *dpy, int scr, FcPattern *pattern, 
	      void *v, int count_chars, XftTextEncoding encoding)
{
   XftPatternSet *set;
   XftText *text;
   CharProp *charprop;
   int i, num_textitems = 0;
   
   set = XftCreatePatternSet(pattern);
   charprop = getCharProp(set, v, count_chars, encoding);
   
   for(i=0; i<count_chars; ++i)
       if (charprop[i].count_chars) ++num_textitems;
   
   text = g_new0(XftText, 1);
   text->num_textitems = num_textitems;
   text->textitems = g_new0(XftTextItem, num_textitems);
   
   num_textitems = 0;
   for(i=0; i < count_chars; ++i)
     {
	if (charprop[i].count_chars)
	  {
	      FcPattern *match;
	      FcResult result;
	      XftTextItem *item = &text->textitems[num_textitems];

	      item->encoding = encoding;
	     
	      switch (encoding)
	       {
		case String8:
		  {
		     char *string = (char *)v;
		     item->text = g_strndup(string, count_chars);
		  }
		  break;
		case String16:
		  {
		     FcChar16 *string = (FcChar16 *)v;

		     item->text = g_new0(FcChar16, count_chars + 1);
		     memcpy(item->text, string, count_chars * sizeof(FcChar16)/sizeof(char));
		  }
		  break;
		case String32:
		  {
		     FcChar32 *string = (FcChar32 *)v;

		     item->text = g_new0(FcChar32, count_chars + 1);
		     memcpy(item->text, string, count_chars * sizeof(FcChar32)/sizeof(char));
		  }
		  break;
		case StringUtf8:
	          {
		     char *string = (char *)v;
	     	     char *start = (char *)g_utf8_offset_to_pointer(string, i);
	             char *end = (char *)g_utf8_offset_to_pointer(string, i + charprop[i].count_chars);
	    
	             item->text = g_new0(char, end - start + 1);
	             g_utf8_strncpy((char *)item->text, start, charprop[i].count_chars);
	    	  } 
		  break;
		case StringUtf16:
		  // not implemented yet
		  break;
	       }

	     match = XftFontMatch(dpy, scr, 
			set->patterns[charprop[i].pattern_index], &result);
	     if (match) 
		 {
	     	    item->font = XftFontOpenPattern(dpy, match);
		    FcPatternDestroy(match);
		 }
	       
	     ++num_textitems;
	  }
     }   
  
   g_free(charprop);
   XftFreePatternSet(set);
   
   return text;
}

void
XftDrawText(XftDraw *draw, _Xconst XftColor *color, XftText *text, int x, int y)
{
   int i, xx = x, yy = y;
   
   for(i=0; i < text->num_textitems; ++i)
     {
	XftFont *font;
	Display *dpy = XftDrawDisplay(draw);
	XGlyphInfo extents;
	int len;
	
	font = text->textitems[i].font;
	switch (text->textitems[i].encoding)
	  {
	   case String8:
	     {
		char *string = (char *)text->textitems[i].text;
		
		len = strlen(string);
		XftDrawString8(draw, color, font, xx, yy, string, len);
		XftTextExtentsUtf8(dpy, font, string, len, &extents);
	     }
	     break;
	   case String16:
	     {
		FcChar16 *string = (FcChar16 *)text->textitems[i].text;

		len = 0;
		while (string[len] != (FcChar16)0) ++len;
		
		XftDrawString16(draw, color, font, xx, yy, string, len);
		XftTextExtents16(dpy, font, string, len, &extents);
	     }
	     break;
	   case String32:
	     {
		FcChar32 *string = (FcChar32 *)text->textitems[i].text;

		len = 0;
		while (string[len] != (FcChar32)0) ++len;
		
		XftDrawString32(draw, color, font, xx, yy, string, len);
		XftTextExtents32(dpy, font, string, len, &extents);
	     }
	     break;
	   case StringUtf8:
	     {
		char *string = (char *)text->textitems[i].text;
		
		len = strlen(string);
		
		XftDrawStringUtf8(draw, color, font, xx, yy, string, len);
		XftTextExtentsUtf8(dpy, font, string, len, &extents);
	     }
	     break;
	   case StringUtf16:
	     // not implemented yet
	     break;
	  }
	
	xx += extents.xOff;
     }
}

void
XftFreeText(Display *dpy, XftText *text)
{
   int i;
   
   if (!text) return;
   
   for (i=0; i < text->num_textitems; ++i)
     {
	XftTextItem textitem = text->textitems[i];
	
	if (textitem.text) g_free(textitem.text);
	XftFontClose(dpy, textitem.font);
     }
   
   g_free(text->textitems);
   g_free(text);
}
-------------- next part --------------
#ifndef _Xfttext_H_
#define _Xfttext_H_

#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include <X11/Xft/XftCompat.h>

typedef enum {String8, String16, String32, StringUtf8, StringUtf16 } XftTextEncoding;

typedef struct _XftTextItem {
   XftFont         *font;
   void            *text;
   XftTextEncoding encoding; /* specify the encoding of 'text' */
} XftTextItem;

typedef struct _XftText {   
   int         num_textitems;
   XftTextItem *textitems;
} XftText;

extern XftText *XftCreateText(Display *, int, FcPattern *, void *, int, XftTextEncoding);
extern void XftDrawText(XftDraw *, _Xconst XftColor *, XftText *, int, int);
extern void XftFreeText(Display *dpy, XftText *);

#endif


More information about the Fontconfig mailing list