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