This is a multi-part message in MIME format. --------------89A6484203A15FCE7F7A254B Content-Type: text/plain; charset=gb2312 Content-Transfer-Encoding: 7bit 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 --------------89A6484203A15FCE7F7A254B Content-Type: text/plain; charset=gb2312; name="xfttext.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="xfttext.c" #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); } --------------89A6484203A15FCE7F7A254B Content-Type: text/plain; charset=gb2312; name="Xfttext.h" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Xfttext.h" #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 --------------89A6484203A15FCE7F7A254B--