Back to index

plt-scheme  4.2.1
Font.cc
Go to the documentation of this file.
00001  /*                                                     -*- C++ -*-
00002  *
00003  * Purpose: wxWindows font handling
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "Font.h"
00029 #endif
00030 
00031 #define  Uses_XLib
00032 #define  Uses_wxFont
00033 #define  Uses_wxFontDirectory
00034 #define  Uses_wxWindowDC
00035 #include "wx.h"
00036 
00037 #ifdef WX_USE_XFT
00038 # include <X11/Xft/Xft.h>
00039 #endif
00040 
00041 char *wx_font_spec [] = {
00042     "wxDEFAULT",
00043     // families
00044     "wxDECORATIVE", "wxMODERN", "wxROMAN", "wxSCRIPT", "wxSWISS", "wxTELETYPE",
00045     // style
00046     "wxNORMAL", "wxSLANT", "wxITALIC",
00047     // weight
00048     "wxNORMAL", "wxBOLD", "wxLIGHT",
00049     // More families
00050     "wxSYSTEM", "wxSYMBOL"
00051 };
00052 
00053 // local function prototypes
00054 static XFontStruct *wxLoadQueryNearestFont(const char *main_screen_name,
00055                                       int point_size, double scale_x, double scale_y,
00056                                       int fontid, int family,
00057                                       int style, int weight, 
00058                                       Bool underlined, Bool size_in_pixels,
00059                                       double angle);
00060 #ifdef WX_USE_XFT
00061 static wxFontStruct *wxLoadQueryNearestAAFont(const char *main_screen_name,
00062                                          int point_size, double scale_x, double scale_y,
00063                                          int style, int weight, 
00064                                          Bool underlined, int smoothing, 
00065                                          Bool size_in_pixels,
00066                                          double angle);
00067 #endif
00068 
00069 //-----------------------------------------------------------------------------
00070 // Face list for substitutions
00071 //-----------------------------------------------------------------------------
00072 
00073 #ifdef WX_USE_XFT
00074 
00075 static int complete_face_list_size;
00076 static char **complete_face_list;
00077 static wxFontStruct **complete_font_list;
00078 
00079 char **wxGetCompleteFaceList(int *_len, int mono_only)
00080 {
00081   char buf[256], *s, *copy;
00082   int ssize, i, j, pos, len, scalable;
00083   XftFontSet *fs;
00084   int face_list_size;
00085   char **face_list;
00086   wxFontStruct **font_list;
00087 
00088   if (complete_face_list && !mono_only) {
00089     if (_len)
00090       *_len = complete_face_list_size;
00091     return complete_face_list;
00092   }
00093 
00094   if (mono_only) {
00095     fs = XftListFonts(wxAPP_DISPLAY, DefaultScreen(wxAPP_DISPLAY), 
00096                       XFT_SPACING, XftTypeInteger, XFT_MONO, NULL,
00097                       /* I'm assuming that every family is either
00098                          scalable or not. We inspect scalability
00099                          to bias substitution to scalable fonts */
00100                       XFT_FAMILY, XFT_SCALABLE,
00101                       NULL);
00102   } else {
00103     fs = XftListFonts(wxAPP_DISPLAY, DefaultScreen(wxAPP_DISPLAY), NULL,
00104                       XFT_FAMILY, XFT_SCALABLE,
00105                       NULL);
00106   }
00107 
00108   face_list_size = fs->nfont;
00109   face_list = new WXGC_PTRS char*[face_list_size];
00110   font_list = (wxFontStruct **)(new WXGC_ATOMIC char[sizeof(wxFontStruct*) * face_list_size]);
00111 
00112   pos = 0;
00113   for (i = 0; i < fs->nfont; i++) {
00114     s = buf;
00115     ssize = 256;
00116     do {
00117       if (XftNameUnparse(fs->fonts[i], s, ssize))
00118        break;
00119       ssize *= 2;
00120       s = new WXGC_ATOMIC char[ssize];
00121     } while (1);
00122 
00123     len = strlen(s);
00124 
00125     scalable = ((len > 2) && (s[len - 2] == 'u')); /* "u" in "...True" */
00126     
00127     /* Get scalability, then truncate at ':' */
00128     for (j = 0; j < len; j++) {
00129       if (s[j] == ':')
00130        break;
00131     }
00132     len = j;
00133 
00134     /* Add a space at the font to indicate "Xft" */
00135     copy = new WXGC_ATOMIC char[len + 2];
00136     memcpy(copy + 1, s, len);
00137     copy[0] = ' ';
00138     copy[len + 1] = 0;
00139 
00140     if (scalable) {
00141       face_list[pos] = copy;
00142       font_list[pos] = NULL;
00143       pos++;
00144     } else {
00145       /* unscalable at end, to discourage use in substitutions */
00146       j = fs->nfont - (i - pos) - 1;
00147       face_list[j] = copy;
00148       font_list[j] = NULL;
00149     }
00150   }
00151   XftFontSetDestroy(fs);
00152 
00153   if (!mono_only) {
00154     wxREGGLOB(complete_face_list);
00155     wxREGGLOB(complete_font_list);
00156     complete_face_list_size = face_list_size;
00157     complete_face_list = face_list;
00158     complete_font_list = font_list;
00159   }
00160 
00161   if (_len)
00162     *_len = face_list_size;
00163   return face_list;
00164 }
00165 
00166 static wxFontStruct *prev_subs;
00167 static Display *prev_subs_display;
00168 
00169 static wxFontStruct *doFindAAFont(Display *dpy, wxFontStruct *xfont, int c, int *index)
00170 {
00171   wxFontStruct *naya;
00172   int i;
00173 
00174   wxGetCompleteFaceList(NULL, 0);
00175 
00176   for (i = 0; i < complete_face_list_size; i++) {
00177     if (!complete_font_list[i]) {
00178       naya = wxLoadQueryNearestAAFont(complete_face_list[i], 
00179                                   13, 1.0, 1.0,
00180                                   wxNORMAL, wxNORMAL_WEIGHT,
00181                                   FALSE, wxSMOOTHING_DEFAULT,
00182                                   TRUE, 0.0);
00183       complete_font_list[i] = naya;
00184     }
00185     
00186     if (XftGlyphExists(dpy, complete_font_list[i], c)) {
00187       /* Need the right size, weight, etc. */
00188       int sz, wt, sl, sip;
00189       XftPattern *pat;
00190       XftResult res;
00191 
00192       if (index) {
00193        *index = i;
00194        return xfont;
00195       }
00196 
00197       if (XftPatternGetInteger(xfont->pattern, XFT_PIXEL_SIZE, 0, &sz) 
00198          == XftResultMatch) {
00199        sip = 1;
00200       } else if (XftPatternGetInteger(xfont->pattern, XFT_SIZE, 0, &sz) 
00201                == XftResultMatch) {
00202        sip = 0;
00203       } else {
00204        sz = 13;
00205        sip = 1;
00206       }
00207       if (XftPatternGetInteger(xfont->pattern, XFT_WEIGHT, 0, &wt)
00208          != XftResultMatch) {
00209        wt = XFT_WEIGHT_MEDIUM;
00210       }
00211       if (XftPatternGetInteger(xfont->pattern, XFT_SLANT, 0, &sl)
00212          != XftResultMatch) {
00213        sl = XFT_SLANT_ROMAN;
00214       }
00215 
00216       if ((sz == 13) && sip
00217          && (wt == XFT_WEIGHT_MEDIUM)
00218          && (sl == XFT_SLANT_ROMAN))
00219        return complete_font_list[i];
00220 
00221       if (prev_subs) {
00222        XftFontClose(prev_subs_display, prev_subs);
00223        prev_subs = NULL;
00224       }
00225 
00226 
00227       pat = XftNameParse(complete_face_list[i] XFORM_OK_PLUS 1);
00228       pat = XftPatternBuild(pat,
00229                          (sip ? XFT_PIXEL_SIZE : XFT_SIZE), XftTypeInteger, sz,
00230                          XFT_WEIGHT, XftTypeInteger, wt,
00231                          XFT_SLANT, XftTypeInteger, sl,
00232                          NULL);
00233       pat = XftFontMatch(wxAPP_DISPLAY, DefaultScreen(dpy), pat, &res);
00234       prev_subs = XftFontOpenPattern(dpy, pat);
00235       prev_subs_display = dpy;
00236 
00237       return prev_subs ? prev_subs : xfont;
00238     }
00239   }
00240 
00241   return xfont;
00242 }
00243 
00244 extern "C" {
00245   wxFontStruct *wxFindAAFont(Display *dpy, wxFontStruct *xfont, int c)
00246   {
00247     return doFindAAFont(dpy, xfont, c, NULL);
00248   }
00249 };
00250 
00251 
00252 #endif
00253 
00254 //-----------------------------------------------------------------------------
00255 // wxFont create and destroy
00256 //-----------------------------------------------------------------------------
00257 
00258 wxFont::wxFont(void)
00259 {
00260     font_id       = wxDEFAULT;
00261     family        = wxTheFontNameDirectory->GetFamily(font_id);
00262     style         = wxNORMAL;
00263     weight        = wxNORMAL_WEIGHT;
00264     point_size    = 12;
00265     underlined    = FALSE;
00266     rotation      = 0.0;
00267 
00268     InitFont();
00269 }
00270 
00271 wxFont::wxFont(int PointSize, int FontIdOrFamily, int Style, int Weight,
00272               Bool Underlined, int Smoothing, Bool sip, double Rotation)
00273 {
00274     font_id       = FontIdOrFamily;
00275     family        = wxTheFontNameDirectory->GetFamily(FontIdOrFamily);
00276     style         = Style;
00277     weight        = Weight == wxNORMAL ? wxNORMAL_WEIGHT : Weight;
00278     point_size    = PointSize;
00279     underlined    = Underlined;
00280     smoothing     = Smoothing;
00281     size_in_pixels = sip;
00282     rotation      = Rotation;
00283 
00284     InitFont();
00285 }
00286 
00287 wxFont::wxFont(int PointSize, const char *Face, int Family, int Style, 
00288               int Weight, Bool Underlined, int Smoothing, Bool sip)
00289 {
00290     font_id       = wxTheFontNameDirectory->FindOrCreateFontId(Face, Family);
00291     family        = wxTheFontNameDirectory->GetFamily(font_id);
00292     style         = Style;
00293     weight        = Weight == wxNORMAL ? wxNORMAL_WEIGHT : Weight;
00294     point_size    = PointSize;
00295     underlined    = Underlined;
00296     smoothing     = Smoothing;
00297     size_in_pixels = sip;
00298     rotation      = 0.0;
00299 
00300     InitFont();
00301 }
00302 
00303 void wxFont::InitFont(void)
00304 {
00305   wxList *sl;
00306   
00307   __type = wxTYPE_FONT;
00308   
00309   sl = new wxList(wxKEY_STRING, FALSE);
00310   scaled_xfonts = sl;
00311 
00312 #ifdef WX_USE_XFT
00313   sl = new wxList(wxKEY_STRING, FALSE);
00314   scaled_xft_fonts = sl;
00315 #endif
00316 
00317   main_screen_name = wxTheFontNameDirectory->GetScreenName(font_id, weight, style);
00318 }
00319 
00320 wxFont::~wxFont(void)
00321 {
00322   wxNode *node;
00323   node = scaled_xfonts->First();
00324   while (node) {
00325     XFontStruct *xfont;
00326     wxNode *next;
00327     xfont = (XFontStruct*)node->Data();
00328     next = node->Next();
00329     XFreeFont(wxAPP_DISPLAY, xfont);
00330     node = next;
00331   }
00332   DELETE_OBJ scaled_xfonts;
00333 
00334 #ifdef  WX_USE_XFT
00335   node = scaled_xft_fonts->First();
00336   while (node) {
00337     wxFontStruct *xfont;
00338     xfont = (wxFontStruct*)node->Data();
00339     if (xfont != (wxFontStruct *)0x1)
00340       XftFontClose(wxAPP_DISPLAY, xfont);
00341     node = node->Next();
00342   }
00343   DELETE_OBJ scaled_xft_fonts;
00344 
00345   if (substitute_xft_fonts) {
00346     node = substitute_xft_fonts->First();
00347     while (node) {
00348       wxFont *sfont;
00349       sfont = (wxFont*)node->Data();
00350       DELETE_OBJ sfont;
00351       node = node->Next();
00352     }
00353     DELETE_OBJ substitute_xft_fonts;
00354   }
00355 #endif
00356 
00357   if (rotated_fonts) {
00358     node = rotated_fonts->First();
00359     while (node) {
00360       wxFont *rot;
00361       rot = (wxFont*)node->Data();
00362       DELETE_OBJ rot;
00363       node = node->Next();
00364     }
00365     DELETE_OBJ rotated_fonts;
00366   }
00367 }
00368 
00369 char *wxFont::GetFaceString(void)
00370 {
00371   /* If it's one of the portable facelss fonts, return NULL. */
00372   switch (font_id) {
00373   case wxDEFAULT:
00374   case wxDECORATIVE:
00375   case wxMODERN:
00376   case wxROMAN:
00377   case wxSCRIPT:
00378   case wxSWISS:
00379   case wxTELETYPE:
00380   case wxSYSTEM:
00381   case wxSYMBOL:
00382     return NULL;
00383   default:
00384     return wxTheFontNameDirectory->GetFontName(font_id); 
00385   }
00386 }
00387 
00388 Bool wxFont::ScreenGlyphAvailable(int c, Bool)
00389 {
00390   XFontStruct *fontinfo;
00391 #ifdef WX_USE_XFT
00392   wxFontStruct *xfontinfo;
00393 #endif
00394   unsigned int byte1, byte2;
00395   int char_metric_offset;
00396 
00397 #ifdef WX_USE_XFT
00398   xfontinfo = (wxFontStruct*)GetInternalAAFont(1.0, 1.0);
00399   if (xfontinfo)
00400     fontinfo = NULL;
00401   else
00402 #endif
00403     fontinfo = (XFontStruct*)GetInternalFont(1.0, 1.0);
00404 
00405 # ifdef WX_USE_XFT
00406   if (xfontinfo) {
00407     int index = 1;
00408     while (1) {
00409       if (XftGlyphExists(wxAPP_DISPLAY, xfontinfo, c))
00410        return TRUE;
00411       
00412       xfontinfo = (wxFontStruct*)GetNextAASubstitution(index++, c, 1.0, 1.0, 0.0);
00413       if (!xfontinfo)
00414        return FALSE;
00415     }
00416   }
00417 #endif
00418 
00419   byte2 = c & 0xff;
00420   byte1 = c >> 8;
00421 
00422   if ((byte1 < fontinfo->min_byte1) 
00423       || (byte1 > fontinfo->max_byte1))
00424     return FALSE;
00425 
00426   if ((byte2 < fontinfo->min_char_or_byte2) 
00427       || (byte2 > fontinfo->max_char_or_byte2)) {
00428     return FALSE;
00429   }
00430 
00431   if (fontinfo->all_chars_exist
00432       || !fontinfo->per_char)
00433     return TRUE;
00434 
00435   char_metric_offset = ((byte1 - fontinfo->min_byte1)
00436                      * (fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1)
00437                      - fontinfo->min_char_or_byte2
00438                      + byte2);
00439 
00440   if (!fontinfo->per_char[char_metric_offset].width
00441       && !fontinfo->per_char[char_metric_offset].ascent
00442       && !fontinfo->per_char[char_metric_offset].descent)
00443     return FALSE;
00444   
00445   return TRUE;
00446 }
00447 
00448 //-----------------------------------------------------------------------------
00449 // rotation
00450 //-----------------------------------------------------------------------------
00451 
00452 int wxFont::CanRotate()
00453 {
00454   return 1;
00455 }
00456 
00457 wxFont *wxFont::GetRotated(double angle)
00458 {
00459   int int_angle = (int)(angle * 1000);
00460   wxNode *node;
00461   wxFont *rot;
00462 
00463   if (!rotated_fonts) {
00464     rotated_fonts = new wxList(wxKEY_INTEGER);
00465   }
00466 
00467   node = rotated_fonts->Find(int_angle);
00468   if (node)
00469     return (wxFont *)node->Data();
00470 
00471   rot = new wxFont(point_size, font_id, style, weight,
00472                  underlined, smoothing, size_in_pixels, angle);
00473   
00474   rotated_fonts->Append(int_angle, (wxObject*)rot);
00475 
00476   return rot;
00477 }
00478 
00479 //-----------------------------------------------------------------------------
00480 // get internal representation of font
00481 //-----------------------------------------------------------------------------
00482 
00483 static void limit_point_scale(int size, double *scale_x, double *scale_y)
00484 {
00485   if ((size * (*scale_x)) > 256)
00486     *scale_x = 1;
00487   if ((size * (*scale_y)) > 256)
00488     *scale_y = 1;
00489 }
00490 
00491 void *wxFont::GetInternalFont(double scale_x, double scale_y, double angle)
00492 {
00493   char        sbuf[128];
00494   wxNode      *node=NULL;
00495   XFontStruct *xfont;
00496 
00497   if (angle != rotation) {
00498     wxFont *rot;
00499     rot = GetRotated(angle);
00500     return rot->GetInternalFont(scale_x, scale_y, angle);
00501   }
00502 
00503   limit_point_scale(point_size, &scale_x, &scale_y);
00504   sprintf(sbuf, "%g %g", scale_x, scale_y);
00505 
00506   if ((node = scaled_xfonts->Find(sbuf))) {
00507     xfont = (XFontStruct*)node->Data();
00508   } else {
00509     xfont = wxLoadQueryNearestFont(main_screen_name,
00510                                point_size, scale_x, scale_y, 
00511                                font_id, family, style, weight,
00512                                underlined, size_in_pixels, angle);
00513     scaled_xfonts->Append(sbuf, (wxObject*)xfont);
00514   }
00515   return (void*)xfont;
00516 }
00517 
00518 //-----------------------------------------------------------------------------
00519 // get internal representation of font
00520 //-----------------------------------------------------------------------------
00521 
00522 void *wxFont::GetInternalAAFont(double scale_x, double scale_y, double angle)
00523 {
00524 #ifdef WX_USE_XFT
00525   if (wxXRenderHere()) {
00526     char        sbuf[128];
00527     wxNode      *node=NULL;
00528     wxFontStruct *xft_font;
00529 
00530 
00531     if (angle != rotation) {
00532       wxFont *rot;
00533       rot = GetRotated(angle);
00534       return rot->GetInternalAAFont(scale_x, scale_y, angle);
00535     }
00536 
00537     limit_point_scale(point_size, &scale_x, &scale_y);
00538     sprintf(sbuf, "%g %g", scale_x, scale_y);
00539 
00540     if ((node = scaled_xft_fonts->Find(sbuf))) {
00541       xft_font = (wxFontStruct*)node->Data();
00542     } else {
00543       xft_font = wxLoadQueryNearestAAFont(main_screen_name,
00544                                      point_size, scale_x, scale_y, 
00545                                      style, weight,
00546                                      underlined, smoothing, size_in_pixels, angle);
00547 
00548       /* Record a 0x1 to mean "no AA font": */
00549       if (!xft_font)
00550        xft_font = (wxFontStruct*)0x1;
00551 
00552       scaled_xft_fonts->Append(sbuf, (wxObject*)xft_font);
00553     }
00554     if (xft_font == (wxFontStruct*)0x1)
00555       return NULL;    
00556     return (void*)xft_font;
00557   } else
00558     return NULL;
00559 #else
00560     return GetInternalFont(scale_x, scale_y, angle);
00561 #endif
00562 }
00563 
00564 #ifdef WX_USE_XFT
00565 int wxFont::HasAASubstitutions()
00566 {
00567   char *name;
00568   int i;
00569 
00570   name = main_screen_name;
00571 
00572   if (name[0] == ' ') {
00573     for (i = 1; name[i]; i++) {
00574       if (name[i] == ',')
00575        return 1;
00576     }
00577   }
00578 
00579   return 0;
00580 }
00581 
00582 void *wxFont::GetNextAASubstitution(int index, int cval, double scale_x, double scale_y, double angle)
00583 {
00584   wxFont *subs;
00585   wxNode *node;
00586 
00587   if (!substitute_xft_fonts) {
00588     wxList *sl;
00589     sl = new wxList(wxKEY_INTEGER);
00590     substitute_xft_fonts = sl;
00591   }
00592 
00593   node = substitute_xft_fonts->Find(index);
00594   if (node)
00595     subs = (wxFont *)node->Data();
00596   else {
00597     char *name, *next_name;
00598     int i, c = 0, len;
00599     
00600     name = main_screen_name;
00601 
00602     for (i = 0; name[i]; i++) {
00603       if (name[i] == ',') {
00604        c++;
00605        if (c == index)
00606          break;
00607       }
00608     }
00609     if (!name[i]) {
00610       if (index == c + 1) {
00611        wxGetCompleteFaceList(NULL, 0);
00612        c = -1;
00613        doFindAAFont(wxAPP_DISPLAY, NULL, cval, &c);
00614        if (c >= 0) {
00615          index += c;
00616          node = substitute_xft_fonts->Find(index);
00617          if (node) {
00618            subs = (wxFont *)node->Data();
00619            next_name = NULL;
00620          } else {
00621            subs = NULL;
00622            next_name = complete_face_list[c];
00623          }
00624        } else
00625          return NULL;
00626       } else
00627        return NULL;
00628     } else {
00629       i++;
00630       len = strlen(name XFORM_OK_PLUS i);
00631       next_name = new WXGC_ATOMIC char[len + 2];
00632       memcpy(next_name + 1, name + i, len + 1);
00633       next_name[0] = ' ';
00634       subs = NULL;
00635     }
00636 
00637     if (!subs) {
00638       subs = new wxFont(point_size, next_name, family, style, weight,
00639                      underlined, smoothing, size_in_pixels);
00640       
00641       substitute_xft_fonts->Append(index, (wxObject*)subs);
00642     }
00643   }
00644 
00645   return subs->GetInternalAAFont(scale_x, scale_y, angle);
00646 }
00647 #endif
00648 
00649 //-----------------------------------------------------------------------------
00650 // wxFontList
00651 //-----------------------------------------------------------------------------
00652 
00653 wxFontList::wxFontList(void)
00654 : wxObject(WXGC_NO_CLEANUP)
00655 {
00656   list = new wxChildList;
00657 }
00658 
00659 wxFontList::~wxFontList(void)
00660 {
00661 }
00662 
00663 void wxFontList::AddFont(wxFont *Font) 
00664 { 
00665   list->Append(Font); 
00666   list->Show(Font, -1); /* so it can be collected */
00667 } 
00668 
00669 //-----------------------------------------------------------------------------
00670 // search for font in fontlist
00671 //-----------------------------------------------------------------------------
00672 
00673 wxFont *wxFontList::FindOrCreateFont(int PointSize, int FontIdOrFamily, 
00674                                  int Style, int Weight, Bool underline,
00675                                  int smoothing, Bool sip)
00676 {
00677   wxFont *font;
00678   wxChildNode *node;
00679   int i = 0;
00680   
00681   while ((node = list->NextNode(i))) {
00682     wxFont *each_font;
00683     each_font = (wxFont*)node->Data();
00684     if (each_font &&
00685        each_font->GetPointSize() == PointSize &&
00686        each_font->GetStyle() == Style &&
00687        each_font->GetWeight() == Weight &&
00688        each_font->GetFontId() == FontIdOrFamily &&
00689        each_font->GetUnderlined() == underline &&
00690        each_font->GetSmoothing() == smoothing &&
00691        each_font->GetSizeInPixels() == sip)
00692       return each_font;
00693   }
00694   
00695   font = new wxFont(PointSize, FontIdOrFamily, Style, Weight, underline, smoothing, sip);
00696 
00697 #if WXGARBAGE_COLLECTION_ON
00698   AddFont(font);
00699 #endif
00700 
00701   return font;
00702 }
00703 
00704 wxFont *wxFontList::FindOrCreateFont(int PointSize, const char *Face, 
00705                                  int Family, int Style, int Weight, 
00706                                  Bool underline, int smoothing, Bool sip)
00707 {
00708   int id;
00709   id = wxTheFontNameDirectory->FindOrCreateFontId(Face, Family);
00710 
00711   return FindOrCreateFont(PointSize,
00712                        id,
00713                        Style,
00714                        Weight,
00715                        underline,
00716                        smoothing,
00717                        sip);
00718 }
00719 
00720 //-----------------------------------------------------------------------------
00721 // local utilities
00722 //-----------------------------------------------------------------------------
00723 
00724 #ifdef WX_USE_XFT
00725 
00726 static wxFontStruct *wxLoadQueryNearestAAFont(const char *name,
00727                                          int point_size, double scale_x, double scale_y,
00728                                          int style, int weight,
00729                                          Bool underlined, int smoothing, Bool sip,
00730                                          double angle)
00731 {
00732   wxFontStruct *fs;
00733 
00734   if (name && (name[0] != ' '))
00735     /* Not an Xft font name */
00736     return NULL;
00737 
00738   {
00739     int sl, wt;
00740     const char *ex_tags[2];
00741     int ex_types[2];
00742     long ex_vals[2];
00743     int ex_pos = 0;
00744     XftMatrix rot;
00745     int use_rot = 0;
00746 
00747     wt = ((weight == wxBOLD)
00748          ? XFT_WEIGHT_BOLD
00749          : ((weight == wxLIGHT)
00750             ? XFT_WEIGHT_LIGHT
00751             : XFT_WEIGHT_MEDIUM));
00752     sl = ((style == wxITALIC)
00753          ? XFT_SLANT_ITALIC
00754          : ((weight == wxSLANT)
00755             ? XFT_SLANT_OBLIQUE
00756             : XFT_SLANT_ROMAN));
00757 
00758     ex_tags[0] = NULL;
00759     ex_types[0] = 0;
00760     ex_vals[0] = 0;
00761     ex_tags[1] = NULL;
00762     ex_types[1] = 0;
00763     ex_vals[1] = 0;
00764 
00765     switch (smoothing) {
00766     case wxSMOOTHING_OFF:
00767       ex_vals[ex_pos] = 0;
00768       ex_types[ex_pos] = XftTypeBool;
00769       ex_tags[ex_pos++] = XFT_ANTIALIAS;
00770       break;
00771     case wxSMOOTHING_ON:
00772     case wxSMOOTHING_PARTIAL:
00773       ex_vals[ex_pos] = 1;
00774       ex_types[ex_pos] = XftTypeBool;
00775       ex_tags[ex_pos++] = XFT_ANTIALIAS;
00776       break;
00777     default:
00778       break;
00779     }
00780 
00781     if (angle || (scale_x != 1.0) || (scale_y != 1.0)) {
00782       XftMatrixInit(&rot);
00783       XftMatrixRotate(&rot, cos(angle), sin(angle));
00784       XftMatrixScale(&rot, scale_x, scale_y);
00785       use_rot = 1;
00786     }
00787 
00788     if (name) {
00789       XftPattern *pat;
00790       XftResult res;
00791       
00792       pat = XftNameParse(name XFORM_OK_PLUS 1);
00793       if (!pat) return NULL;
00794 
00795       pat = XftPatternBuild(pat,
00796                          (sip ? XFT_PIXEL_SIZE : XFT_SIZE), XftTypeInteger, point_size,
00797                          XFT_WEIGHT, XftTypeInteger, wt,
00798                          XFT_SLANT, XftTypeInteger, sl,
00799                          ex_tags[0], ex_types[0], ex_vals[0],
00800                          ex_tags[1], ex_types[1], ex_vals[1],
00801                          NULL);
00802 
00803       pat = XftFontMatch(wxAPP_DISPLAY, DefaultScreen(wxAPP_DISPLAY), pat, &res);
00804       if (!pat) return NULL;
00805       
00806       if (use_rot) {
00807        /* We add a transform after match, because Xft/fontconfig
00808           seems to sometimes free a non-malloced pointer if we
00809           include the transformation in the pattern to match. The
00810           transformation presumably doesn't affect matching,
00811           anyway, so adding it now should be fine. */
00812        pat = XftPatternBuild(pat,
00813                            XFT_MATRIX, XftTypeMatrix, &rot,
00814                            NULL);
00815       }
00816 
00817       fs = XftFontOpenPattern(wxAPP_DISPLAY, pat);
00818     } else
00819       fs = NULL;
00820 
00821     if (!fs) {
00822       /* accept most any default: */
00823       fs = XftFontOpen(wxAPP_DISPLAY, DefaultScreen(wxAPP_DISPLAY),
00824                      (sip ? XFT_PIXEL_SIZE : XFT_SIZE), XftTypeInteger, point_size,
00825                      XFT_WEIGHT, XftTypeInteger, wt,
00826                      XFT_SLANT, XftTypeInteger, sl,
00827                      ex_tags[0], ex_types[0], ex_vals[0],
00828                      ex_tags[1], ex_types[1], ex_vals[1],
00829                      NULL);
00830     }
00831   }
00832   
00833   return fs;
00834 }
00835 
00836 #endif
00837 
00838 static XFontStruct *wxLoadQueryFont(const char *name,
00839                                 int point_size, double scale_x, double scale_y,
00840                                 int fontid, int style,
00841                                 int weight, Bool underlined, 
00842                                 int si_try_again, Bool sip, double angle)
00843 {
00844   char *buffer;
00845   long len, i, found = 0;
00846   XFontStruct *s;
00847 
00848   if (!name)
00849     name = wxTheFontNameDirectory->GetScreenName(fontid, weight, style);
00850 
00851   if (!name)
00852     name = "-*-*-*-*-*-*-*-%d-*-*-*-*-*-*";
00853 
00854   len = strlen(name);
00855   buffer = new WXGC_ATOMIC char[len + 128];
00856 
00857   /* Make sure there's %d and no other format directives: */
00858   for (i = 0; i < len; i++) {
00859     if (name[i] == '%') {
00860       if (name[i + 1] == '%')
00861        i++;
00862       else if (name[i + 1] == 'd') {
00863        if (found)
00864          return NULL;
00865        found = i + 1;
00866       } else
00867        return NULL;
00868     }
00869   }
00870 
00871   /* If the size is in pixels, try to change
00872      ...-*-%d-... to ...-%d-*-... */
00873   if (sip && found) {
00874     if ((found > 4) 
00875        && (name[found+1] == '-')
00876        && (name[found-2] == '-')
00877        && (name[found-3] == '*')
00878        && (name[found-4] == '-')) {
00879       char *rename;
00880       rename = new WXGC_ATOMIC char[len + 1];
00881       memcpy(rename, name, len + 1);
00882       rename[found-3] = '%';
00883       rename[found-2] = 'd';
00884       rename[found-1] = '-';
00885       rename[found] = '*';
00886       name = rename;
00887     } else
00888       sip = 0;
00889   } else
00890     sip = 0;
00891 
00892   if (found && ((angle != 0.0) 
00893               || (scale_x != 1.0)
00894               || (scale_y != 1.0))) {
00895     /* Replace %d with %s: */
00896     char *rename, *matrix_str;
00897     double matrix[4];
00898     
00899     rename = new WXGC_ATOMIC char[len + 1];
00900     memcpy(rename, name, len + 1);
00901     for (i = 0; i < len; i++) {
00902       if (rename[i] == '%') {
00903        if (rename[i + 1] == 'd') {
00904          rename[i + 1] = 's';
00905          break;
00906        }
00907        i++;
00908       }
00909     }
00910 
00911     matrix[0] = ((double)point_size * scale_x) * cos(angle);
00912     matrix[1] = ((double)point_size * scale_y) * sin(angle);
00913     matrix[2] = -((double)point_size * scale_x) * sin(angle);
00914     matrix[3] = ((double)point_size * scale_y) * cos(angle);
00915 
00916     matrix_str = new WXGC_ATOMIC char[128];
00917     sprintf(matrix_str, "[%g %g %g %g]", 
00918            matrix[0], matrix[1],
00919            matrix[2], matrix[3]);
00920     for (i = 0; matrix_str[i]; i++) {
00921       if (matrix_str[i] == '-')
00922        matrix_str[i] = '~';
00923     }
00924     
00925     sprintf(buffer, rename, matrix_str);
00926   } else {
00927     sprintf(buffer, name, 
00928            (sip ? point_size : point_size * 10));
00929   }
00930 
00931   s = XLoadQueryFont(wxAPP_DISPLAY, buffer);
00932 
00933   if (!s && si_try_again && ((style == wxSLANT) || (style == wxITALIC))) {
00934     /* Try slant/italic instead of italic/slant: */
00935     s = wxLoadQueryFont(NULL, point_size, scale_x, scale_y, 
00936                      fontid, (style == wxSLANT) ? wxITALIC : wxSLANT, 
00937                      weight, underlined, 
00938                      0, sip, angle);
00939   }
00940 
00941   return s;
00942 }
00943 
00944 static XFontStruct *wxLoadQueryNearestFont(const char *name,
00945                                       int point_size, double scale_x, double scale_y,
00946                                       int fontid, int family,
00947                                       int style, int weight,
00948                                       Bool underlined, Bool sip, double angle)
00949 {
00950   XFontStruct *font;
00951   int tried_once = 0;
00952 
00953   while (1) {
00954 
00955     font = wxLoadQueryFont(name, point_size, scale_x, scale_y, 
00956                         fontid, style, weight, underlined, 
00957                         1, sip, angle);
00958 
00959     if (!font) {
00960       // search up and down by stepsize 1
00961       int max_size = point_size + 2 * (1 + (point_size/18));
00962       int min_size = point_size - 2 * (1 + (point_size/18));
00963       int i;
00964 
00965       // Try plain style
00966       font = wxLoadQueryFont(NULL, point_size, scale_x, scale_y, 
00967                           fontid, wxNORMAL, wxNORMAL_WEIGHT, underlined, 
00968                           1, sip, angle);
00969 
00970       // Search for smaller size (approx.)
00971       for (i=point_size-1; !font && i >= 1 && i >= min_size; i -= 1) {
00972        font = wxLoadQueryFont(name, i, scale_x, scale_y,
00973                             fontid, style, weight, underlined, 
00974                             1, sip, angle);
00975        if (!font)
00976          font = wxLoadQueryFont(NULL, i, scale_x, scale_y, fontid,
00977                              wxNORMAL, wxNORMAL_WEIGHT, underlined, 
00978                              1, sip, angle);
00979       }
00980       // Search for larger size (approx.)
00981       for (i=point_size+1; !font && i <= max_size; i += 1) {
00982        font = wxLoadQueryFont(name, i, scale_x, scale_y, 
00983                             fontid, style, weight, underlined, 
00984                             1, sip, angle);
00985        if (!font)
00986          font = wxLoadQueryFont(NULL, i, scale_x, scale_y, 
00987                              fontid,  wxNORMAL, wxNORMAL_WEIGHT, underlined, 
00988                              1, sip, angle);
00989       }
00990     }
00991     
00992     if (font || tried_once)
00993       break;
00994     else {
00995       tried_once = 1;
00996       fontid = family;
00997     }
00998   }
00999 
01000   /* Last-ditch efforts */
01001   if (!font) {
01002     char buffer[40];
01003     sprintf(buffer, "-*-*-*-*-*-*-*-%d-*-*-*-*-*-*", point_size * 10);
01004     font = XLoadQueryFont(wxAPP_DISPLAY, buffer);
01005     
01006     if (!font) /* really last-ditch */
01007       font = XLoadQueryFont(wxAPP_DISPLAY, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
01008   }
01009 
01010   return font;
01011 }
01012 
01013 int wxGetControlFontSize()
01014 {
01015   return wxNORMAL_FONT->GetPointSize();
01016 }