summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2005-10-13 13:51:59 +0000
committerMatthias Melcher <fltk@matthiasm.com>2005-10-13 13:51:59 +0000
commit55f6d7673d7ac3564858ca30c9f564f0910d7219 (patch)
treefe1560a0a24501086253954c2deb608f355b95a7
parent405b80784abdb70a9aa5a09abb9e060c60153187 (diff)
STR #1012 (Xft): added provided Xft code and cleaned it
up a little. Event though the author mentions a few flaws, this is far better than what we had in here before and makes the Xft support actually usable. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4592 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--src/fl_set_fonts_xft.cxx281
1 files changed, 257 insertions, 24 deletions
diff --git a/src/fl_set_fonts_xft.cxx b/src/fl_set_fonts_xft.cxx
index 8c38b26d0..7fbd88c01 100644
--- a/src/fl_set_fonts_xft.cxx
+++ b/src/fl_set_fonts_xft.cxx
@@ -26,6 +26,8 @@
//
#include <X11/Xft/Xft.h>
+#include <string.h>
+#include <ctype.h>
// This function fills in the fltk font table with all the fonts that
// are found on the X server. It tries to place the fonts into families
@@ -50,6 +52,9 @@ const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
case 'P': type = FL_BOLD | FL_ITALIC; break;
default: type = 0; break;
}
+
+ // NOTE: This can cause duplications in fonts that already have Bold or Italic in
+ // their "name". Maybe we need to find a cleverer way?
strlcpy(f->fontname, p+1, ENDOFBUFFER);
if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER);
if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER);
@@ -59,32 +64,260 @@ const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
return f->fontname;
}
-#if 0
+///////////////////////////////////////////////////////////
+#define LOCAL_RAW_NAME_MAX 256
+
extern "C" {
-static int sort_function(const void *aa, const void *bb) {
- const char* name_a = (*(Fl_Fontdesc**)aa)->name;
- const char* name_b = (*(Fl_Fontdesc**)bb)->name;
- int ret = strcasecmp(name_a+1, name_b+1); if (ret) return ret;
- return name_a[0]-name_b[0]; // sort by attribute
-}
-}
+// sort returned fontconfig font names
+static int name_sort(const void *aa, const void *bb) {
+ // What should we do here? Just do a string compare for now...
+ // NOTE: This yeilds some oddities - in particular a Blah Bold font will be
+ // listed before Blah...
+ // Also - the fontconfig listing returns some faces that are effectively duplicates
+ // as far as fltk is concerned, e.g. where there are ko or ja variants that we
+ // can't distinguish (since we are not yet fully UTF-*) - should we strip them here?
+ return strcasecmp(*(char**)aa, *(char**)bb);
+} // end of name_sort
+} // end of extern C section
-static Fl_Fontdesc* make_a_font(char attrib, const char* name) {
- Fl_Fontdesc* newfont = new Fl_Fontdesc;
- char *n = new char[strlen(name)+2];
- n[0] = attrib;
- strcpy(n+1, name);
- newfont->name = n;
- newfont->first = 0;
- return newfont;
-}
-#endif // 0
+// Read the "pretty" name we have derived from fontconfig then convert
+// it into the format fltk uses internally for Xft names...
+// This is just a mess - I should have tokenised the strings and gone from there,
+// but I really thought this would be easier!
+static void make_raw_name(char *raw, char *pretty)
+{
+ // Input name will be "Some Name:style = Bold Italic" or whatever
+ // The plan is this:
+ // - the first char in the "raw" name becomes either I, B, P or " " for
+ // italic, bold, bold italic or normal - this seems to be the fltk way...
-Fl_Font Fl::set_fonts(const char* xstarname) {
- // TODO: implement this for Xft...
- return FL_FREE_FONT;
-}
+ char *style = strchr(pretty, ':');
+ char *last = style + strlen(style) - 2;
+
+ if (style)
+ {
+ *style = 0; // Terminate "name" string
+ style ++; // point to start of style section
+ }
+ raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text
+ strncat(raw, pretty, LOCAL_RAW_NAME_MAX);
+ // At this point, the name is "marked" as regular...
+ if (style)
+ {
+#define PLAIN 0
+#define BOLD 1
+#define ITALIC 2
+#define BITALIC (BOLD | ITALIC)
+ int mods = PLAIN;
+ // Now try and parse the style string - look for the "=" sign
+ style = strchr(style, '=');
+ while ((style) && (style < last))
+ {
+ int type;
+ while ((*style == '=') || (*style == ' ') || (*style == '\t'))
+ {
+ style++; // Start of Style string
+ if ((style >= last) || (*style == 0)) continue;
+ }
+ type = toupper(style[0]);
+ switch (type)
+ {
+ // Things we might see: Regular Normal Bold Italic Oblique (??what??) Medium
+ // Roman Light Demi Sans SemiCondensed SuperBold Book... etc...
+ // Things we actually care about: Bold Italic Oblique SuperBold - Others???
+ case 'I':
+ if (strncasecmp(style, "Italic", 6) == 0)
+ {
+ mods |= ITALIC;
+ }
+ goto NEXT_STYLE;
+
+ case 'B':
+ if (strncasecmp(style, "Bold", 4) == 0)
+ {
+ mods |= BOLD;
+ }
+ goto NEXT_STYLE;
+
+ case 'O':
+ if (strncasecmp(style, "Oblique", 7) == 0)
+ {
+ mods |= ITALIC;
+ }
+ goto NEXT_STYLE;
+
+ case 's':
+ if (strncasecmp(style, "SuperBold", 9) == 0)
+ {
+ mods |= BOLD;
+ }
+ goto NEXT_STYLE;
+
+ default: // find the next gap
+ goto NEXT_STYLE;
+ } // switch end
+NEXT_STYLE:
+ while ((*style != ' ') && (*style != '\t'))
+ {
+ style++;
+ if ((style >= last) || (*style == 0)) goto STYLE_DONE;
+ }
+ }
+STYLE_DONE:
+ // Set the "modifier" character in the raw string
+ switch(mods)
+ {
+ case BOLD: raw[0] = 'B';
+ break;
+ case ITALIC: raw[0] = 'I';
+ break;
+ case BITALIC: raw[0] = 'P';
+ break;
+ default: raw[0] = ' ';
+ break;
+ }
+ }
+} // make_raw_name
+
+///////////////////////////////////////////////////////////
+
+static int fl_free_font = FL_FREE_FONT;
+
+// Uses the fontconfig lib to construct a list of all installed fonts.
+// I tried using XftListFonts for this, but the API is tricky - and when I looked
+// at the XftList* code, it calls the Fc* functions anyway... so...
+// Also, for now I'm ignoring the "pattern_name" and just getting everything...
+// AND I don't try and skip the fonts we've already loaded in the defaults.
+// Blimey! What a hack!
+Fl_Font Fl::set_fonts(const char* pattern_name)
+{
+ FcFontSet *fnt_set; // Will hold the list of fonts we find
+ FcPattern *fnt_pattern; // Holds the generic "match all names" pattern
+ FcObjectSet *fnt_obj_set = 0; // Holds the generic "match all objects"
+
+ int j; // loop iterator variable
+ int font_count; // Total number of fonts found to process
+ char **full_list; // The list of font names we build
+
+ if (fl_free_font > FL_FREE_FONT) // already been here
+ return (Fl_Font)fl_free_font;
+
+ fl_open_display(); // Just in case...
+
+ // Make sure fontconfig is ready... is this necessary? The docs say it is
+ // safe to call it multiple times, so just go for it anyway!
+ if (!FcInit ())
+ {
+ // What to do? Just return defaults...
+ return FL_FREE_FONT;
+ }
+
+ // Create a search pattern that will match every font name - I think this does the
+ // Right Thing... but am not certain...
+ // This could possibly be "enhanced" to pay attention to the requested "pattern_name"?
+ fnt_pattern = FcPatternCreate ();
+ fnt_obj_set = FcObjectSetBuild (FC_FAMILY, FC_STYLE, 0);
+
+ // Hopefully, this is a set of all the fonts...
+ fnt_set = FcFontList (0, fnt_pattern, fnt_obj_set);
+
+ // We don't need the fnt_pattern any more, release it
+ FcPatternDestroy (fnt_pattern);
+
+ // Now, if we got any fonts, iterate through them...
+ if (fnt_set)
+ {
+ char *stop;
+ char *start;
+ char *first;
+
+ font_count = fnt_set->nfont; // How many fonts?
+
+ // Allocate array of char*'s to hold the name strings
+ full_list = (char **)malloc(sizeof(char *) * font_count);
+
+ // iterate through all the font patterns and get the names out...
+ for (j = 0; j < font_count; j++)
+ {
+ // NOTE: FcChar8 is a typedef of "unsigned char"...
+ FcChar8 *font; // String to hold the font's name
+
+ // Convert from fontconfig internal pattern to human readable name
+ // NOTE: This WILL malloc storage, so we need to free it later...
+ font = FcNameUnparse (fnt_set->fonts[j]);
+
+ // The returned strings look like this...
+ // Century Schoolbook:style=Bold Italic,fed kursiv,Fett Kursiv,...
+ // So the bit we want is up to the first comma - BUT some strings have
+ // more than one name, separated by, guess what?, a comma...
+ stop = start = first = 0;
+ stop = strchr((const char *)font, ',');
+ start = strchr((const char *)font, ':');
+ if ((stop) && (start) && (stop < start))
+ {
+ first = stop + 1; // discard first version of name
+ // find first comma *after* the end of the name
+ stop = strchr((const char *)start, ',');
+ }
+ else
+ {
+ first = (char *)font; // name is just what was returned
+ }
+ // Truncate the name after the (english) modifiers description
+ if (stop)
+ {
+ *stop = 0; // Terminate the string at the first comma, if there is one
+ }
+
+ // Copy the font description into our list
+ if (first == (char *)font)
+ { // The listed name is still OK
+ full_list[j] = (char *)font;
+ }
+ else
+ { // The listed name has been modified
+ full_list[j] = strdup(first);
+ // Free the font name storage
+ free (font);
+ }
+ // replace "style=Regular" so strcmp sorts it first
+ if (start) {
+ char *reg = strstr(full_list[j], "=Regular");
+ if (reg) reg[1]='.';
+ }
+ }
+
+ // Release the fnt_set - we don't need it any more
+ FcFontSetDestroy (fnt_set);
+
+ // Sort the list into alphabetic order
+ qsort(full_list, font_count, sizeof(*full_list), name_sort);
+
+ // Now let us add the names we got to fltk's font list...
+ for (j = 0; j < font_count; j++)
+ {
+ if (full_list[j])
+ {
+ char xft_name[LOCAL_RAW_NAME_MAX];
+ char *stored_name;
+ // Parse the strings into FLTK-XFT style..
+ make_raw_name(xft_name, full_list[j]);
+ // NOTE: This just adds on AFTER the default fonts - no attempt is made
+ // to identify already loaded fonts. Is this bad?
+ stored_name = strdup(xft_name);
+ Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name);
+ fl_free_font ++;
+
+ free(full_list[j]); // release that name from our internal array
+ }
+ }
+ // Now we are done with the list, release it fully
+ free (full_list);
+ }
+ return (Fl_Font)fl_free_font;
+} // ::set_fonts
+////////////////////////////////////////////////////////////////
extern "C" {
@@ -104,8 +337,8 @@ int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) {
fl_open_display();
XftFontSet* fs = XftListFonts(fl_display, fl_screen,
- XFT_FAMILY, XftTypeString, s->name+1, 0,
- XFT_PIXEL_SIZE, 0);
+ XFT_FAMILY, XftTypeString, s->name+1, 0,
+ XFT_PIXEL_SIZE, 0);
static int* array = 0;
static int array_size = 0;
if (fs->nfont >= array_size) {