Index: src/Fl_Font.H
===================================================================
--- src/Fl_Font.H	(revision 10174)
+++ src/Fl_Font.H	(working copy)
@@ -28,6 +28,30 @@
 
 #  if USE_XFT
 typedef struct _XftFont XftFont;
+/**
+   This is a structure for an XFT font, with info about it's encoding and
+   character sizes.  Each XftFontList has an array of these.
+*/
+typedef struct _XftMatch
+{
+  XftFont*    font;
+  const char* enc_str;         // Encoding name
+  const char* lang_str;        // FontConfig language name
+  int         enc_num;         // XUTF8 encoding number
+  int         ascent;
+  int         descent;
+  int         offset;          // Adjustment from baseline
+} XftMatch;
+/**
+   This a structure that represents a collection of XFT fonts.
+*/
+typedef struct _XftFontList
+{
+  XftMatch* matches;
+  int       count;
+  int       ascent;
+  int       descent;
+} XftFontList;
 #  elif !defined(WIN32) && !defined(__APPLE__)
 #    include <FL/Xutf8.h>
 #  endif // USE_XFT
@@ -61,8 +85,7 @@
   ATSUStyle style;
   short ascent, descent, q_width;
 #  elif USE_XFT
-  XftFont* font;
-  //const char* encoding;
+  XftFontList* font;
   int angle;
   FL_EXPORT Fl_Font_Descriptor(const char* xfontname, Fl_Fontsize size, int angle);
 #  else
Index: src/Fl_PostScript.cxx
===================================================================
--- src/Fl_PostScript.cxx	(revision 10174)
+++ src/Fl_PostScript.cxx	(working copy)
@@ -941,11 +941,13 @@
     fprintf(output, "/%s SF\n" , _fontNames[f]);
 #if defined(USE_X11) 
 #if USE_XFT
+#  if 0  // XXX FIXME
     // Xft font height is sometimes larger than the required size (see STR 2566).
     // Increase the PostScript font size by 15% without exceeding the display font height 
     int max = desc->font->height;
     ps_size = s * 1.15;
     if (ps_size > max) ps_size = max;
+#  endif
 #else
     // Non-Xft fonts can be smaller than required.
     // Set the PostScript font size to the display font height 
Index: src/fl_font_x.cxx
===================================================================
--- src/fl_font_x.cxx	(revision 10174)
+++ src/fl_font_x.cxx	(working copy)
@@ -294,7 +294,6 @@
   if (font_gc != fl_gc) {
     if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
     font_gc = fl_gc;
-    XSetFont(fl_display, fl_gc, font_descriptor()->font->fid);
   }
   int xx, yy, ww, hh;
   xx = yy = ww = hh = 0;
Index: src/fl_font_xft.cxx
===================================================================
--- src/fl_font_xft.cxx	(revision 10174)
+++ src/fl_font_xft.cxx	(working copy)
@@ -52,6 +52,13 @@
 // itself. You should edit the ~/.xftconfig file to "fix" things, there
 // are several web pages of information on how to do this.
 //
+
+//
+// This file contains a port of the STR #1903 Xft fontset patch from Timothy Lee
+// to r10174. It should allow transparent glyph substitution (without using
+// Pango).
+//
+
 #ifndef FL_DOXYGEN
 
 #include <X11/Xft/Xft.h>
@@ -60,43 +67,60 @@
 
 // The predefined fonts that FLTK has:
 static Fl_Fontdesc built_in_table[] = {
-#if 1
-{" sans"},
-{"Bsans"},
-{"Isans"},
-{"Psans"},
-{" mono"},
-{"Bmono"},
-{"Imono"},
-{"Pmono"},
-{" serif"},
-{"Bserif"},
-{"Iserif"},
-{"Pserif"},
-{" symbol"},
-{" screen"},
-{"Bscreen"},
-{" zapf dingbats"},
-#else
-{" helvetica"},
-{"Bhelvetica"},
-{"Ihelvetica"},
-{"Phelvetica"},
-{" courier"},
-{"Bcourier"},
-{"Icourier"},
-{"Pcourier"},
-{" times"},
-{"Btimes"},
-{"Itimes"},
-{"Ptimes"},
-{" symbol"},
-{" lucidatypewriter"},
-{"Blucidatypewriter"},
-{" zapf dingbats"},
-#endif
+  {" sans"},
+  {"Bsans"},
+  {"Isans"},
+  {"Psans"},
+  {" mono"},
+  {"Bmono"},
+  {"Imono"},
+  {"Pmono"},
+  {" serif"},
+  {"Bserif"},
+  {"Iserif"},
+  {"Pserif"},
+  {" symbol"},
+  {" screen"},
+  {"Bscreen"},
+  {" zapf dingbats"}
 };
 
+#define current_font (fl_graphics_driver->font_descriptor()->font)
+
+static const char* enc_strings[] = {
+  "iso8859-1",       "fr",
+  "iso8859-2",       "pl",
+  "iso8859-3",       "eo",
+  "iso8859-4",       "lt",
+  "iso8859-5",       "bg",
+  "iso8859-6",       "",
+  "iso8859-7",       "gr",
+  "iso8859-8",       "he",
+  "iso8859-9",       "tr",
+  "iso8859-10",      "",
+  "iso8859-11",      "",
+  "iso8859-13",      "lt",
+  "iso8859-14",      "ga",
+  "iso8859-15",      "fr",
+  "koi8-r",          "ru-ru",
+  "big5-0",          "zh-tw",
+  "ksc5601.1987-0",  "ko",
+  "gb2312.1980-0",   "zh-cn",
+  "jisx0201.1976-0", "ja",
+  "symbol",          "",
+  "dingbats",        "",
+  "koi8-u",          "ru-ua",
+  "iso10646-1",      "",
+  NULL
+};
+
+// Characters for estimating font height and width (as per Pango)
+static unsigned int extent_test_chars[] = {
+  '0', '1', '8', 'a', 'd', 'x', 'm', 'y', 'g', 'W', 'X', '\'', '_',
+  0x00cd, 0x00d5, 0x0114, 0x0177, 0x0643, 0x304c, 0x672c,   // �.�.�.ŷ�.�..�.�.
+  '\0'
+};
+
 Fl_Fontdesc* fl_fonts = built_in_table;
 
 Fl_XFont_On_Demand fl_xfont;
@@ -104,8 +128,13 @@
 //const char* fl_encoding_ = "iso8859-1";
 const char* fl_encoding_ = "iso10646-1";
 
+extern "C" {
+  int ucs2fontmap(char *s, unsigned int ucs, int enc);
+  int encoding_number(const char* enc);
+}
+
 static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) {
-  if (fnum==-1) { // special case to stop font caching
+  if (fnum == -1) { // special case to stop font caching
     driver->Fl_Graphics_Driver::font(0, 0);
     return;
   }
@@ -137,7 +166,37 @@
   fl_xft_font(this,fnum,size,0);
 }
 
-static XftFont* fontopen(const char* name, Fl_Fontsize size, bool core, int angle) {
+static void fill_match_metrics(XftMatch* rec) {
+  rec->ascent   = 0;
+  rec->descent  = 0;
+  rec->offset   = 0;
+
+  // Calculate ascent and descent from test glyphs
+  for (unsigned int* ucs = extent_test_chars;  *ucs;  ucs++) {
+    // Ignore characters not used by current encoding
+    char dummy[2];
+    if (ucs2fontmap(dummy, *ucs, rec->enc_num) < 0)  continue;
+    FcChar32   c = *ucs;
+    XGlyphInfo g;
+    XftTextExtents32(fl_display, rec->font, &c, 1, &g);
+    int ascent = g.y;
+    int descent = g.height - g.y;
+    if (ascent > rec->ascent)  rec->ascent = ascent;
+    if (descent > rec->descent)  rec->descent = descent;
+  }
+
+  // When ascent and descent not found, trust the font
+  if (rec->ascent == 0 && rec->descent == 0) {
+    rec->ascent  = rec->font->ascent;
+    rec->descent = rec->font->descent;
+  }
+}
+
+static XftFontList* fontopen(const char* name, Fl_Fontsize size, bool core, int angle) {
+#if 1 // diagnostic to print the requested "name" of the font.
+  printf("\nRequested name: %s\n", name);
+#endif
+
   // Check: does it look like we have been passed an old-school XLFD fontname?
   bool is_xlfd = false;
   int hyphen_count = 0;
@@ -152,9 +211,8 @@
 
   fl_open_display();
 
+  XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching
   if(!is_xlfd) { // Not an XLFD - open as a XFT style name
-    XftFont *the_font; // the font we will return;
-    XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching
     int slant = XFT_SLANT_ROMAN;
     int weight = XFT_WEIGHT_MEDIUM;
 
@@ -170,11 +228,11 @@
      */
     /* This may be efficient, but it is non-obvious. */
     switch (*name++) {
-    case 'I': slant = XFT_SLANT_ITALIC; break; // italic
-    case 'P': slant = XFT_SLANT_ITALIC;        // bold-italic (falls-through)
-    case 'B': weight = XFT_WEIGHT_BOLD; break; // bold
-    case ' ': break;                           // regular
-    default: name--;                           // no prefix, restore name
+      case 'I': slant = XFT_SLANT_ITALIC; break; // italic
+      case 'P': slant = XFT_SLANT_ITALIC;        // bold-italic (falls-through)
+      case 'B': weight = XFT_WEIGHT_BOLD; break; // bold
+      case ' ': break;                           // regular
+      default: name--;                           // no prefix, restore name
     }
 
     if(comma_count) { // multiple comma-separated names were passed
@@ -188,26 +246,25 @@
           nxt++; // first char of next name
         }
 
-	// Add the current name to the match pattern
-	XftPatternAddString(fnt_pat, XFT_FAMILY, curr);
+        // Add the current name to the match pattern
+        XftPatternAddString(fnt_pat, XFT_FAMILY, curr);
 
         if(nxt) curr = nxt; // move onto next name (if it exists)
-	// Now do a cut-down version of the FLTK name conversion.
-	// NOTE: we only use the slant and weight of the first name,
-	// subsequent names we ignore this for... But we still need to do the check.
+        // Now do a cut-down version of the FLTK name conversion.
+        // NOTE: we only use the slant and weight of the first name,
+        // subsequent names we ignore this for... But we still need to do the check.
         switch (*curr++) {
-        case 'I': break; // italic
-        case 'P':        // bold-italic (falls-through)
-        case 'B': break; // bold
-        case ' ': break; // regular
-        default: curr--; // no prefix, restore name
+          case 'I': break; // italic
+          case 'P':        // bold-italic (falls-through)
+          case 'B': break; // bold
+          case ' ': break; // regular
+          default: curr--; // no prefix, restore name
         }
 
         comma_count--; // decrement name sections count
       } while (comma_count >= 0);
       free(local_name); // release our local copy of font names
-    }
-    else { // single name was passed - add it directly
+    } else { // single name was passed - add it directly
       XftPatternAddString(fnt_pat, XFT_FAMILY, name);
     }
 
@@ -215,7 +272,6 @@
     XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight);
     XftPatternAddInteger(fnt_pat, XFT_SLANT, slant);
     XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)size);
-    XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_);
 
     // rotate font if angle!=0
     if (angle !=0) {
@@ -229,99 +285,126 @@
       XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue);
       XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse);
     }
+  } else {
+    if(comma_count) { // multiple comma-separated XLFDs were passed
+      char *local_name = strdup(name); // duplicate the full name so we can edit the copy
+      char *curr = local_name; // points to first name in string
+      char *nxt; // next name in string
+      do {
+        nxt = strchr(curr, ','); // find comma separator
+        if (nxt) {
+          *nxt = 0; // terminate first name
+          nxt++; // first char of next name
+        }
 
-    XftPattern *match_pat;  // the best available match on the system
-    XftResult match_result; // the result of our matching attempt
+        // Add the current name to the match pattern
+        XftPatternAddString(fnt_pat, XFT_XLFD, curr);
 
-    // query the system to find a match for this font
-    match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result);
+        if (nxt) curr = nxt; // move onto next name (if it exists)
 
-#if 0 // the XftResult never seems to get set to anything... abandon this code?
-    switch(match_result) { // how good a match is this font for our request?
-      case XftResultMatch:
-	puts("Object exists with the specified ID");
-	break;
+        comma_count--; // decrement name sections count
+      } while (comma_count >= 0);
+      free(local_name); // release our local copy of font names
+    } else { // single name was passed - add it directly
+      XftPatternAddString(fnt_pat, XFT_XLFD, name);
+    }
+  }
 
-      case XftResultTypeMismatch:
-	puts("Object exists, but the type does not match");
-	break;
+  XftPattern *match_pat;  // the best available match on the system
+  XftResult match_result; // the result of our matching attempt
 
-      case XftResultNoId:
-	puts("Object exists, but has fewer values than specified");
-	break;
+  // query the system to find a matching font for each encoding
+  XftFontList* list = (XftFontList*)calloc(1, sizeof(XftFontList));
+  for (int n = 0;  enc_strings[n];  n += 2) {
+    // Attempt to find a font for the required encoding
+    XftFont* fnt = NULL;
+    int enc_num = encoding_number(enc_strings[n]);
+    if (enc_num >= 0) {
+      XftPatternDel(fnt_pat, FC_LANG);
+      if (strlen(enc_strings[n+1])) {
+        XftPatternAddString(fnt_pat, FC_LANG, enc_strings[n + 1]);
+      }
+      match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result);
 
-      case FcResultOutOfMemory:
-	puts("FcResult: Malloc failed");
-	break;
-
-      case XftResultNoMatch:
-	puts("Object does not exist at all");
-	break;
-
-      default:
-	printf("Invalid XftResult status %d \n", match_result);
-	break;
-    }
+#if 1 // the XftResult never seems to get set to anything... abandon this code?
+      // Note: This works as intended on Micha's system
+      switch (match_result) {
+        case XftResultMatch:
+          //puts("Object exists with the specified ID");
+          break;
+        case XftResultTypeMismatch:
+          puts("Object exists, but the type does not match");
+          break;
+        case XftResultNoId:
+          puts("Object exists, but has fewer values than specified");
+          break;
+        case FcResultOutOfMemory:
+          puts("FcResult: Malloc failed");
+          break;
+        case XftResultNoMatch:
+          puts("Object does not exist at all");
+          break;
+        default:
+          printf("Invalid XftResult status %d \n", match_result);
+          break;
+      }
+      // Errors are currently ignored
 #endif
 
 #if 0 // diagnostic to print the "full name" of the font we matched. This works.
-    FcChar8 *picked_name =  FcNameUnparse(match_pat);
-    printf("Match: %s\n", picked_name);
-    free(picked_name);
+      FcChar8 *picked_name =  FcNameUnparse(match_pat);
+      printf("\nMatch: %s\n", picked_name);
+      free(picked_name);
 #endif
 
-    if (!match_pat) {
-      // last chance, just open any font in the right size
-      the_font = XftFontOpen (fl_display, fl_screen,
-                        XFT_FAMILY, XftTypeString, "sans",
-                        XFT_SIZE, XftTypeDouble, (double)size,
-                        NULL);
-      XftPatternDestroy(fnt_pat);
-      if (!the_font) {
+      if (!match_pat) {
         Fl::error("Unable to find fonts. Check your FontConfig configuration.\n");
         exit(1);
+      } else {
+        // open the matched font
+        fnt = XftFontOpenPattern(fl_display, match_pat);
+        if (!fnt)  XftPatternDestroy(match_pat);
       }
-      return the_font;
     }
 
-    // open the matched font
-    the_font = XftFontOpenPattern(fl_display, match_pat);
-
 #if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
-    FcChar8 *picked_name2 =  FcNameUnparse(the_font->pattern);
-    printf("Open : %s\n", picked_name2);
+    FcChar8 *picked_name2 =  FcNameUnparse(fnt->pattern);
+    printf("\nOpen : %s\n", picked_name2);
     free(picked_name2);
 #endif
 
-    XftPatternDestroy(fnt_pat);
-//  XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not!
+    // When a matching font is found, append to font list
+    if (fnt) {
+#if 1 // diagnostic message
+      FcChar8* filename;
+      printf("\n");
+      if (FcPatternGetString(fnt->pattern, FC_FILE, 0, &filename)
+          == FcResultMatch) {
+        printf("Appending for '%s'\x09: %s", enc_strings[n + 1], filename);
+      }
+#endif
+      list->count ++;
+      list->matches = (XftMatch*) realloc(list->matches,
+                                          sizeof(XftMatch) * list->count);
+      XftMatch& rec = list->matches[list->count - 1];
+      rec.font = fnt;
+      rec.enc_str = enc_strings[n];
+      rec.lang_str = enc_strings[n + 1];
+      rec.enc_num = enc_num;
+      fill_match_metrics(&rec);
 
-    return the_font;
+      // Update ascent and descent of combined font set
+      if (rec.ascent > list->ascent)  { list->ascent  = rec.ascent; }
+      if (rec.descent > list->descent)  { list->descent = rec.descent; }
+    }
   }
-  else { // We were passed a font name in XLFD format
-    /* OksiD's X font code could handle being passed a comma separated list
-     * of XLFD's. It then attempted to find which font was "best" from this list.
-     * But XftFontOpenXlfd can not do this, so if a list is passed, we just
-     * terminate it at the first comma.
-     * A "better" solution might be to use XftXlfdParse() on each of the passed
-     * XLFD's to construct a "super-pattern" that incorporates attributes from all
-     * XLFD's and use that to perform a XftFontMatch(). Maybe...
-     */
-    char *local_name = strdup(name);
-    if(comma_count) { // This means we were passed multiple XLFD's
-      char *pc = strchr(local_name, ',');
-      *pc = 0; // terminate the XLFD at the first comma
-    }
-    XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name);
-    free(local_name);
-#if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
-puts("Font Opened"); fflush(stdout);
-    FcChar8 *picked_name2 =  FcNameUnparse(the_font->pattern);
-    printf("Open : %s\n", picked_name2); fflush(stdout);
-    free(picked_name2);
+#if 1 // diagnostic to print the number of fonts in the fontset.
+  printf("\nNumber of fonts in fontset: %d\n", list->count);
 #endif
-   return the_font;
-  }
+
+  // Tidy up the resources we allocated
+  XftPatternDestroy(fnt_pat);
+  return list;
 } // end of fontopen
 
 Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize fsize, int fangle) {
@@ -337,6 +420,8 @@
 Fl_Font_Descriptor::~Fl_Font_Descriptor() {
   if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL);
 //  XftFontClose(fl_display, font);
+  free(font->matches);
+  free(font);
 }
 
 /* decodes the input UTF-8 string into a series of wchar_t characters.
@@ -362,16 +447,18 @@
   return buffer;
 }
 
+#if 0  // No longer required?
 static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyphInfo *extents)
 {
   memset(extents, 0, sizeof(XGlyphInfo));
   const wchar_t *buffer = utf8reformat(str, n);
 #ifdef __CYGWIN__
-    XftTextExtents16(fl_display, desc->font, (XftChar16 *)buffer, n, extents);
+    XftTextExtents16(fl_display, desc->font->matches->font, (XftChar16 *)buffer, n, extents);
 #else
-    XftTextExtents32(fl_display, desc->font, (XftChar32 *)buffer, n, extents);
+    XftTextExtents32(fl_display, desc->font->matches->font, (XftChar32 *)buffer, n, extents);
 #endif
 }
+#endif
 
 int Fl_Xlib_Graphics_Driver::height() {
   if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent;
@@ -383,11 +470,205 @@
   else return -1;
 }
 
+static int fl_width(XftFont* fnt, FcChar32* str, int n) {
+  XGlyphInfo i;
+  XftTextExtents32(fl_display, fnt, str, n, &i);
+  return i.xOff;
+}
+
+// This function is used internally to avoid duplicate code in fl_width()
+// and fl_draw().  A non-NULL XftDraw parameter causes the actual string to
+// be drawn
+static double fl_width_utf8_(const char* str, int n,
+  XftDraw* draw = NULL, XftColor* color = NULL, int x = 0, int y = 0)
+{
+  XftMatch* matches;      // fonts array
+  FcChar32  buf[128];     // drawing buffer
+  int       i;            // current byte in the UCS buffer
+  int       fnum;         // index of the current font in the fonts array
+  int       last_fnum;    // font index of the previous char
+  int       count;        // quantity of fonts in the font array
+  char      glyph[2];     // byte1 and byte2 value of the UTF-8 char
+  int       org_x = x;
+
+#if 1 // diagnostic to print the string.
+  printf("\nfl_width_utf8_(): %s\n", str);
+#endif
+
+  if (!current_font)  return -1.0;
+  count = current_font->count;
+
+  // There are no fonts in current_font
+  if (count < 1)  return -1.0;
+
+  matches = current_font->matches;
+  i = 0;
+  fnum = 0;
+
+  while((fnum < count) && !matches[fnum].font) ++fnum;
+  if (fnum >= count) {
+    /* there is no valid font inside the XFT font set */
+    return 0;
+  }
+
+  last_fnum = fnum;
+
+  while (n > 0) {
+    int          ulen;    /* byte length of the UTF-8 char */
+    unsigned int ucs;     /* Unicode value of the UTF-8 char */
+    unsigned int no_spc;  /* Spacing char equivalent of a non-spacing char */
+
+    if (i > 120) {
+      /*** draw the buffer **/
+      if (draw)
+        XftDrawString32(draw, color, matches[fnum].font, x, y, buf, i);
+      x += fl_width(matches[fnum].font, buf, i);
+      i = 0;
+    }
+
+    ulen = XFastConvertUtf8ToUcs((unsigned char*)str, n, &ucs);
+    if (ulen < 1) ulen = 1;
+
+    no_spc = XUtf8IsNonSpacing(ucs);
+    if (no_spc) ucs = no_spc;
+
+    // Find the first encoding which can be used to draw the glyph
+    for (fnum = 0;  fnum < count;  fnum++)
+    {
+      if (matches[fnum].enc_num == 0) continue;
+      if (ucs2fontmap(glyph, ucs, matches[fnum].enc_num) >= 0) break;
+    }
+    if (fnum == count) {
+      // The char is invalid in all encodings, draw with the first font
+      fnum = 0;
+      ucs = '?';
+    }
+
+    if ((last_fnum != fnum) || no_spc) {
+     if (draw)
+        XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+      x += fl_width(matches[last_fnum].font, buf, i);
+      i = 0;
+      *buf = ucs;
+      if (no_spc) {
+        // Go back to draw the non-spacing char over the previous char
+        x -= fl_width(matches[fnum].font, buf, 1);
+      }
+    } else {
+      *(buf + i) = ucs;
+    }
+    last_fnum = fnum;
+    i++;
+    str += ulen;
+    n -= ulen;
+  }
+
+ if (draw)
+    XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+  x += fl_width(matches[fnum].font, buf, i);
+
+  return (x - org_x);
+}
+
+// This function is used internally to avoid duplicate code in fl_width()
+// and fl_drawUCS4().  A non-NULL XftDraw parameter causes the actual string to
+// be drawn
+static double fl_width_32_(const FcChar32* str, int n,
+  XftDraw* draw = NULL, XftColor* color = NULL, int x = 0, int y = 0)
+{
+  XftMatch* matches;      // fonts array
+  FcChar32  buf[128];     // drawing buffer
+  int       i;            // current byte in the UCS buffer
+  int       fnum;         // index of the current font in the fonts array
+  int       last_fnum;    // font index of the previous char
+  int       count;        // quantity of fonts in the font array
+  char      glyph[2];     // byte1 and byte2 value of the UTF-8 char
+  int       org_x = x;
+
+  if (!current_font)  return -1.0;
+  count = current_font->count;
+
+  // There are no fonts in current_font
+  if (count < 1)  return -1.0;
+
+  matches = current_font->matches;
+  i = 0;
+  fnum = 0;
+
+  while((fnum < count) && !matches[fnum].font) ++fnum;
+  if (fnum >= count) {
+    /* there is no valid font inside the XFT font set */
+    return 0;
+  }
+
+  last_fnum = fnum;
+
+  while (n > 0) {
+    unsigned int ucs;     /* Current UCS character */
+    unsigned int no_spc;  /* Spacing char equivalent of a non-spacing char */
+
+    if (i > 120) {
+      /*** draw the buffer **/
+      if (draw)
+        XftDrawString32(draw, color, matches[fnum].font, x, y, buf, i);
+      x += fl_width(matches[fnum].font, buf, i);
+      i = 0;
+    }
+
+    ucs = *str;
+    no_spc = XUtf8IsNonSpacing(ucs);
+    if (no_spc) ucs = no_spc;
+
+    // Find the first encoding which can be used to draw the glyph
+    for (fnum = 0;  fnum < count;  fnum++)
+    {
+      if (matches[fnum].enc_num == 0) continue;
+      if (ucs2fontmap(glyph, ucs, matches[fnum].enc_num) >= 0) break;
+    }
+    if (fnum == count) {
+      // The char is invalid in all encodings, draw with the first font
+      fnum = 0;
+      ucs = '?';
+    }
+
+    if ((last_fnum != fnum) || no_spc) {
+      if (draw)
+        XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+      x += fl_width(matches[last_fnum].font, buf, i);
+      i = 0;
+      *buf = ucs;
+      if (no_spc) {
+        // Go back to draw the non-spacing char over the previous char
+        x -= fl_width(matches[fnum].font, buf, 1);
+      }
+    } else {
+      *(buf + i) = ucs;
+    }
+    last_fnum = fnum;
+    i++;
+    ++str;
+    --n;
+  }
+
+  if (draw)
+    XftDrawString32(draw, color, matches[last_fnum].font, x, y, buf, i);
+  x += fl_width(matches[fnum].font, buf, i);
+
+  return (x - org_x);
+}
+
+static double fl_xft_width(const char *str, int n) {
+  return fl_width_utf8_(str, n);
+}
+
 double Fl_Xlib_Graphics_Driver::width(const char* str, int n) {
+#if 0
   if (!font_descriptor()) return -1.0;
   XGlyphInfo i;
   utf8extents(font_descriptor(), str, n, &i);
   return i.xOff;
+#endif
+  return fl_xft_width(str, n);
 }
 
 /*double fl_width(uchar c) {
@@ -394,10 +675,14 @@
   return fl_graphics_driver->width((const char *)(&c), 1);
 }*/
 
+// double fl_width(uchar c) {
+// double fl_width(FcChar32 *str, int n) {
+// double fl_width(unsigned int c) {
+
 static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) {
   if (!desc) return -1.0;
   XGlyphInfo i;
-  XftTextExtents32(fl_display, desc->font, str, n, &i);
+  XftTextExtents32(fl_display, desc->font->matches->font, str, n, &i);
   return i.xOff;
 }
 
@@ -411,13 +696,10 @@
     dx = dy = 0;
     return;
   }
-  XGlyphInfo gi;
-  utf8extents(font_descriptor(), c, n, &gi);
-
-  w = gi.width;
-  h = gi.height;
-  dx = -gi.x;
-  dy = -gi.y;
+  w = (int)fl_width_utf8_(c, n);
+  h = fl_height();
+  dx = 0;
+  dy = 0;
 } // fl_text_extents
 
 
@@ -603,13 +885,16 @@
   color.color.green = ((int)g)*0x101;
   color.color.blue  = ((int)b)*0x101;
   color.color.alpha = 0xffff;
-  
+
+#if 0
   const wchar_t *buffer = utf8reformat(str, n);
 #ifdef __CYGWIN__
-  XftDrawString16(draw_, &color, font_descriptor()->font, x, y, (XftChar16 *)buffer, n);
+  XftDrawString16(draw_, &color, font_descriptor()->font->matches->font, x, y, (XftChar16 *)buffer, n);
 #else
-  XftDrawString32(draw_, &color, font_descriptor()->font, x, y, (XftChar32 *)buffer, n);
+  XftDrawString32(draw_, &color, font_descriptor()->font->matches->font, x, y, (XftChar32 *)buffer, n);
 #endif
+#endif
+  fl_width_utf8_(str, n, draw_, &color, x, y);
 }
 
 void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
@@ -649,7 +934,7 @@
   color.color.blue  = ((int)b)*0x101;
   color.color.alpha = 0xffff;
 
-  XftDrawString32(draw_, &color, driver->font_descriptor()->font, x, y, (FcChar32 *)str, n);
+  fl_width_32_(str, n, draw_, &color, x, y);
 }
 
 
Index: test/Makefile
===================================================================
--- test/Makefile	(revision 10174)
+++ test/Makefile	(working copy)
@@ -46,6 +46,7 @@
 	fast_slow.cxx \
 	file_chooser.cxx \
 	fonts.cxx \
+	fontset.cxx \
 	forms.cxx \
 	fractals.cxx \
 	fullscreen.cxx \
@@ -118,6 +119,7 @@
 	fast_slow$(EXEEXT) \
 	file_chooser$(EXEEXT) \
 	fonts$(EXEEXT) \
+	fontset$(EXEEXT) \
 	forms$(EXEEXT) \
 	hello$(EXEEXT) \
 	help$(EXEEXT) \
@@ -343,6 +345,8 @@
 
 fonts$(EXEEXT): fonts.o
 
+fontset$(EXEEXT): fontset.o
+
 forms$(EXEEXT): forms.o
 	echo Linking $@...
 	$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ forms.o $(LINKFLTKFORMS) $(LDLIBS)
Index: test/fontset.cxx
===================================================================
--- test/fontset.cxx	(revision 0)
+++ test/fontset.cxx	(working copy)
@@ -0,0 +1,34 @@
+//
+// This program should demonstrate Xft glyph substitution.
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file.  If this
+// file is missing or damaged, see the license at:
+//
+//     http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+//     http://www.fltk.org/str.php
+//
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Box.H>
+
+const char label[] = "Hello Xft, RU: \xd1\x80\xd1\x83\xcc\x81\xd1\x81\xd1\x81"
+  "\xd0\xba\xd0\xb8\xd0\xb9, JP: \xe6\x97\xa5\xe6\x9c\xac\xe5\x9b\xbd";
+
+int main(int argc, char **argv) {
+  Fl_Window *window = new Fl_Window(740,140);
+  Fl_Box *box = new Fl_Box(20,40,700,60,label);
+  box->box(FL_UP_BOX);
+  //box->labelfont(FL_BOLD+FL_ITALIC);
+  //box->labeltype(FL_SHADOW_LABEL);
+  box->labelsize(20);
+  window->end();
+  window->show(argc, argv);
+  return Fl::run();
+}
