DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: http://www.fltk.org/str.php?L1903
Version: 1.3-feature





Link: http://www.fltk.org/str.php?L1903
Version: 1.3-feature
Index: src/Fl_Font.H
===================================================================
--- src/Fl_Font.H       (revision 6655)
+++ src/Fl_Font.H       (working copy)
@@ -37,6 +37,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
@@ -73,8 +97,7 @@
   char *q_name;
   int size;
 #  elif USE_XFT
-  XftFont* font;
-  const char* encoding;
+  XftFontList* font;
   Fl_Fontsize size;
   FL_EXPORT Fl_Font_Descriptor(const char* xfontname);
 #  else
Index: src/fl_font_xft.cxx
===================================================================
--- src/fl_font_xft.cxx (revision 6655)
+++ src/fl_font_xft.cxx (working copy)
@@ -89,6 +89,42 @@
 
 #define current_font (fl_fontsize->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_Font fl_font_ = 0;
 Fl_Fontsize fl_size_ = 0;
 //XFontStruct* fl_xfont = 0;
@@ -98,6 +134,11 @@
 const char* fl_encoding_ = "iso10646-1";
 Fl_Font_Descriptor* fl_fontsize = 0;
 
+extern "C" {
+  int ucs2fontmap(char *s, unsigned int ucs, int enc);
+  int encoding_number(const char* enc);
+}
+
 void fl_font(Fl_Font fnum, Fl_Fontsize size) {
   if (fnum==-1) { // special case to stop font caching
     fl_font_ = 0; fl_size_ = 0;
@@ -127,7 +168,36 @@
   fl_xftfont = (void*)f->font;
 }
 
-static XftFont* fontopen(const char* name, bool core) {
+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, bool core) {
   // Check: does it look like we have been passed an old-school XLFD fontname?
   bool is_xlfd = false;
   int hyphen_count = 0;
@@ -142,9 +212,8 @@
 
   fl_open_display();
 
-  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
+  if(!is_xlfd) { // Not an XLFD - open as a XFT style name
     int slant = XFT_SLANT_ROMAN;
     int weight = XFT_WEIGHT_MEDIUM;
 
@@ -205,17 +274,51 @@
     XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight);
     XftPatternAddInteger(fnt_pat, XFT_SLANT, slant);
     XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)fl_size_);
-    XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_);
 
     if (core) {
       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
+        }
+
+        // Add the current name to the match pattern
+        XftPatternAddString(fnt_pat, XFT_XLFD, curr);
+
+        if(nxt) curr = nxt; // move onto next name (if it exists)
+
+        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);
+    }
+  }
 
     XftPattern *match_pat;  // the best available match on the system
     XftResult match_result; // the result of our matching attempt
 
-    // query the system to find a match for this font
+  // 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);
 
 #if 0 // the XftResult never seems to get set to anything... abandon this code?
@@ -252,8 +355,12 @@
     free(picked_name);
 #endif
 
+      if (match_pat) {
     // open the matched font
-    the_font = XftFontOpenPattern(fl_display, match_pat);
+        fnt = XftFontOpenPattern(fl_display, match_pat);
+        if (!fnt)  XftPatternDestroy(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);
@@ -261,35 +368,29 @@
     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)
+    {
+      list->count ++;
+      list->matches = (XftMatch*)realloc(list->matches,
+         sizeof(XftMatch) * list->count);
 
-    return the_font;
-  }
-  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
+      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);
+
+      // 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;
     }
-    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);
-#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) {
@@ -304,6 +405,8 @@
 Fl_Font_Descriptor::~Fl_Font_Descriptor() {
   if (this == fl_fontsize) fl_fontsize = 0;
 //  XftFontClose(fl_display, font);
+  free(font->matches);
+  free(font);
 }
 
 int fl_height() {
@@ -316,26 +419,205 @@
   else return -1;
 }
 
-double fl_width(const char *str, int n) {
-  if (!current_font) return -1.0;
+static int
+fl_width(XftFont* fnt, FcChar32* str, int n)
+{
   XGlyphInfo i;
-  XftTextExtentsUtf8(fl_display, current_font, (XftChar8 *)str, n, &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 (!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);
+}
+
+double fl_width(const char *str, int n) {
+  return fl_width_utf8_(str, n);
+}
+
 double fl_width(uchar c) {
-  return fl_width((const char *)(&c), 1);
+  return fl_width_utf8_((const char*)(&c), 1);
 }
 
 double fl_width(FcChar32 *str, int n) {
-  if (!current_font) return -1.0;
-  XGlyphInfo i;
-  XftTextExtents32(fl_display, current_font, str, n, &i);
-  return i.xOff;
+  return fl_width_32_(str, n);
 }
 
 double fl_width(unsigned int c) {
-  return fl_width((FcChar32 *)(&c), 1);
+  return fl_width_32_((FcChar32 *)(&c), 1);
 }
 
 void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
@@ -344,13 +626,10 @@
     dx = dy = 0;
     return;
   }
-  XGlyphInfo gi;
-  XftTextExtentsUtf8(fl_display, current_font, (XftChar8 *)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
 
 
@@ -511,7 +790,7 @@
   color.color.blue  = ((int)b)*0x101;
   color.color.alpha = 0xffff;
 
-  XftDrawStringUtf8(draw, &color, current_font, x, y, (XftChar8 *)str, n);
+  fl_width_utf8_(str, n, draw, &color, x, y);
 }
 
 void fl_draw(const char* str, int n, float x, float y) {
@@ -549,7 +828,7 @@
   color.color.blue  = ((int)b)*0x101;
   color.color.alpha = 0xffff;
 
-  XftDrawString32(draw, &color, current_font, x, y, (FcChar32 *)str, n);
+  fl_width_32_(str, n, draw, &color, x, y);
 }
 
 
Index: src/fl_font_x.cxx
===================================================================
--- src/fl_font_x.cxx   (revision 6655)
+++ src/fl_font_x.cxx   (working copy)
@@ -310,7 +310,6 @@
   if (font_gc != fl_gc) {
     if (!fl_xfont) fl_font(FL_HELVETICA, 14);
     font_gc = fl_gc;
-    XSetFont(fl_display, fl_gc, fl_xfont->fid);
   }
 //  XDrawString(fl_display, fl_window, fl_gc, x, y, c, n);
   XUtf8DrawString(fl_display, fl_window, fl_xfont, fl_gc, x, y, c, n);
_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to