1 /********************************************************************************
2 *                                                                               *
3 *                               F o n t   O b j e c t                           *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXFont.cpp,v 1.104 2005/01/16 16:06:07 fox Exp $                         *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxpriv.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXApp.h"
38 #include "FXId.h"
39 #include "FXFont.h"
40 #include "FXException.h"
41 
42 
43 /*
44   Notes:
45 
46   - Interpretation of the hints:
47 
48       FONTPITCH_DEFAULT     No preference for pitch
49       FONTPITCH_FIXED       If specified, match for fixed pitch fonts are strongly preferred
50       FONTPITCH_VARIABLE    If specified, match for variable pitch font strongly preferred
51 
52       FONTHINT_DONTCARE     No hints given
53       FONTHINT_DECORATIVE   Ye Olde Fonte
54       FONTHINT_MODERN       Monospace fonts such as courier and so on
55       FONTHINT_ROMAN        Serif font such as times
56       FONTHINT_SCRIPT       Cursive font/script
57       FONTHINT_SWISS        Sans serif font such as swiss, helvetica, arial
58       FONTHINT_SYSTEM       Raster based fonts, typically monospaced
59 
60       FONTHINT_X11          Set internally to force X11-style font specification for font name
61 
62       FONTHINT_SCALABLE     Strong emphasis on scalable fonts; under Windows, this means
63                             TrueType fonts are desired
64 
65       FONTHINT_POLYMORPHIC  Strong emphasis on polymorphic fonts; under Windows, this means
66                             TrueType fonts desired also
67 
68   - For font size, the largest font not larger than the indicated size is taken;
69     rationale is that larger fonts may make applications too big for the screen, but
70     smaller ones are OK.
71 
72   - FONTENCODING_DEFAULT means we prefer the fonts for the current locale;
73     currently, this is hardwired to iso8859-1 until we have some means of
74     determining the preferred encoding from the locale.
75 
76   - FONTSLANT_ITALIC is a cursive typeface for some fonts; FONTSLANT_OBLIQUE is the same
77     basic font written at an angle; for many fonts, FONTSLANT_ITALIC and FONTSLANT_OBLIQUE
78     means pretty much the same thing.  FONTSLANT_DONTCARE indicates a preference for
79     normal, non-cursive fonts.
80 
81   - FONTWEIGHT_DONTCARE indicates a preference for a normal font weight.
82 
83   - XFontStruct.ascent+XFontStruct.descent is the height of the font, as far as line
84     spacing goes.  XFontStruct.max_bounds.ascent+XFontStruct.max_bounds.descent is
85     larger, as some characters can apparently extend beyond ascent or descent!!
86 
87   - We should assume success first, i.e. only fall back on complicated matching if
88     stuff fails; in many cases, fonts are picked from FXFontSelector and already known
89     to exist...
90 
91   - Registry section FONTSUBSTITUTIONS can be used to map typeface names to platform
92     specific typeface names:
93 
94         [FONTSUBSTITUTIONS]
95         arial = helvetica
96         swiss = helvetica
97 
98     This allows you to change fonts in programs with hard-wired fonts.
99 
100   - Text txfm matrix [a b c d] premultiplies.
101 
102   - Should we perhaps build our own tables of font metrics? This might make
103     things simpler for the advanced stuff, and be conceivably a lot faster
104     under MS-Windows [no need to SelectObject() all the time just to get some
105     info; also, this could be useful in case the drawing surface is not a
106     window].
107 
108   - FOR THE MOMENT we're creating a dummy DC to keep the font locked into the GDI
109     for MUCH quicker access to text metrics.  Soon however we want to just build
110     our own font metrics tables and determine the metrics entirely with client-side
111     code.  This will [predictably] be the fastest possible method as it will not
112     involve context switches...
113 
114   - Somehow, create() of fonts assumes its for the screen; how about other
115     surfaces?
116 
117   - Need some API to make OpenGL fonts out of the 2D fonts...
118 
119   - Matching algorithm should favor bitmapped fonts over scalable ones [as the
120     latter may not be optimized easthetically; also, the matching algorithm should
121     not weight resolution as much.
122 
123   - UNICODE means registry and encoding are set to iso10646-1
124 
125   - More human-readable font strings (e.g. registry):
126 
127        family [foundry],size,weight,slant,setwidth,encoding,hints
128 
129     For example:
130 
131        times [urw],120,bold,i,normal,iso8859-1,0
132 
133     Note that the size is in decipoints!
134 
135   - Get encoding from locale (see X11).
136 
137   - Need to be able to specify size in pixels as well as points.
138 
139   - Fonts shown in XListFonts() may *still* not exist!  Need to
140     change create() so it tries various things by XLoadQueryFont()
141     instead of assuming font from XListFonts() used in XLoadQueryFont()
142     will always succeed.
143 */
144 
145 
146 // X11
147 #ifndef WIN32
148 
149 
150 // Hint mask
151 #define FONTHINT_MASK     (FONTHINT_DECORATIVE|FONTHINT_MODERN|FONTHINT_ROMAN|FONTHINT_SCRIPT|FONTHINT_SWISS|FONTHINT_SYSTEM)
152 
153 // Convenience macros
154 #define DISPLAY(app)      ((Display*)((app)->display))
155 
156 
157 
158 #ifdef HAVE_XFT_H
159 
160 
161 // A glyph exists for the given character
162 #define HASCHAR(font,ch)        TRUE    // FIXME
163 #define FIRSTCHAR(font)         0       // FIXME
164 #define LASTCHAR(font)          255     // FIXME
165 
166 
167 #else
168 
169 
170 // Maximum XLFD name length
171 #define MAX_XLFD          512
172 
173 // XLFD Fields
174 #define XLFD_FOUNDRY      0
175 #define XLFD_FAMILY       1
176 #define XLFD_WEIGHT       2
177 #define XLFD_SLANT        3
178 #define XLFD_SETWIDTH     4
179 #define XLFD_ADDSTYLE     5
180 #define XLFD_PIXELSIZE    6
181 #define XLFD_POINTSIZE    7
182 #define XLFD_RESOLUTION_X 8
183 #define XLFD_RESOLUTION_Y 9
184 #define XLFD_SPACING      10
185 #define XLFD_AVERAGE      11
186 #define XLFD_REGISTRY     12
187 #define XLFD_ENCODING     13
188 
189 // Match factors
190 #define ENCODING_FACTOR   1024
191 #define FAMILY_FACTOR     512
192 #define FOUNDRY_FACTOR    256
193 #define PITCH_FACTOR      128
194 #define RESOLUTION_FACTOR 64
195 #define SCALABLE_FACTOR   32
196 #define POLY_FACTOR       16
197 #define SIZE_FACTOR       8
198 #define WEIGHT_FACTOR     4
199 #define SLANT_FACTOR      2
200 #define SETWIDTH_FACTOR   1
201 
202 #define EQUAL1(str,c)     (str[0]==c && str[1]=='\0')
203 #define EQUAL2(str,c1,c2) (str[0]==c1 && str[1]==c2 && str[2]=='\0')
204 
205 // A glyph exists for the given character
206 #define HASCHAR(font,ch)  ((((XFontStruct*)font)->min_char_or_byte2 <= (FXuint)ch) && ((FXuint)ch <= ((XFontStruct*)font)->max_char_or_byte2))
207 #define FIRSTCHAR(font)   (((XFontStruct*)font)->min_char_or_byte2)
208 #define LASTCHAR(font)    (((XFontStruct*)font)->max_char_or_byte2)
209 
210 #endif
211 
212 
213 // MS-Windows
214 #else
215 
216 // A glyph exists for the given character
217 #define HASCHAR(font,ch)  ((((TEXTMETRIC*)font)->tmFirstChar <= (FXuint)ch) && ((FXuint)ch <= ((TEXTMETRIC*)font)->tmLastChar))
218 #define FIRSTCHAR(font)   (((TEXTMETRIC*)font)->tmFirstChar)
219 #define LASTCHAR(font)    (((TEXTMETRIC*)font)->tmLastChar)
220 
221 #endif
222 
223 using namespace FX;
224 
225 
226 namespace FX {
227 
228 // For tables
229 struct ENTRY {
230   const FXchar *name;
231   FXuint        value;
232   };
233 
234 /*******************************************************************************/
235 
236 // Helper functions X11
237 
238 #ifndef WIN32
239 
240 
241 // Get family and foundry from name
familyandfoundryfromname(FXchar * family,FXchar * foundry,const FXchar * name)242 static void familyandfoundryfromname(FXchar* family,FXchar* foundry,const FXchar* name){
243   while(*name && isspace(*name)) name++;
244   if(*name){
245     while(*name && *name!='[') *family++=*name++;
246     while(isspace(*(family-1))) family--;
247     }
248   *family='\0';
249   if(*name=='['){
250     name++;
251     while(*name && isspace(*name)) name++;
252     if(*name){
253       while(*name && *name!=']') *foundry++=*name++;
254       while(isspace(*(foundry-1))) foundry--;
255       }
256     }
257   *foundry='\0';
258   }
259 
260 
261 #ifdef HAVE_XFT_H                       // Using XFT
262 
263 #define FCWIDTHVERSION 10004
264 
265 #if FC_VERSION >= FCWIDTHVERSION
266 
267 // From FOX weight to fontconfig weight
weight2FcWeight(FXint weight)268 static FXint weight2FcWeight(FXint weight){
269   switch(weight){
270     case FONTWEIGHT_THIN:      return FC_WEIGHT_THIN;
271     case FONTWEIGHT_EXTRALIGHT:return FC_WEIGHT_EXTRALIGHT;
272     case FONTWEIGHT_LIGHT:     return FC_WEIGHT_LIGHT;
273     case FONTWEIGHT_NORMAL:    return FC_WEIGHT_NORMAL;
274     case FONTWEIGHT_MEDIUM:    return FC_WEIGHT_MEDIUM;
275     case FONTWEIGHT_DEMIBOLD:  return FC_WEIGHT_DEMIBOLD;
276     case FONTWEIGHT_BOLD:      return FC_WEIGHT_BOLD;
277     case FONTWEIGHT_EXTRABOLD: return FC_WEIGHT_EXTRABOLD;
278     case FONTWEIGHT_HEAVY:     return FC_WEIGHT_HEAVY;
279     }
280   return FC_WEIGHT_NORMAL;
281   }
282 
283 
284 // From fontconfig weight to FOX weight
fcWeight2Weight(FXint fcWeight)285 static FXint fcWeight2Weight(FXint fcWeight){
286   switch(fcWeight){
287     case FC_WEIGHT_THIN:      return FONTWEIGHT_THIN;
288     case FC_WEIGHT_EXTRALIGHT:return FONTWEIGHT_EXTRALIGHT;
289     case FC_WEIGHT_LIGHT:     return FONTWEIGHT_LIGHT;
290     case FC_WEIGHT_NORMAL:    return FONTWEIGHT_NORMAL;
291     case FC_WEIGHT_MEDIUM:    return FONTWEIGHT_MEDIUM;
292     case FC_WEIGHT_DEMIBOLD:  return FONTWEIGHT_DEMIBOLD;
293     case FC_WEIGHT_BOLD:      return FONTWEIGHT_BOLD;
294     case FC_WEIGHT_EXTRABOLD: return FONTWEIGHT_EXTRABOLD;
295     case FC_WEIGHT_BLACK:     return FONTWEIGHT_BLACK;
296     }
297   return FONTWEIGHT_NORMAL;
298   }
299 
300 // From FOX setwidth to fontconfig setwidth
setWidth2FcSetWidth(FXint setwidth)301 static FXint setWidth2FcSetWidth(FXint setwidth){
302   switch(setwidth){
303     case FONTSETWIDTH_ULTRACONDENSED:return FC_WIDTH_ULTRACONDENSED;
304     case FONTSETWIDTH_EXTRACONDENSED:return FC_WIDTH_EXTRACONDENSED;
305     case FONTSETWIDTH_CONDENSED:     return FC_WIDTH_CONDENSED;
306     case FONTSETWIDTH_SEMICONDENSED: return FC_WIDTH_SEMICONDENSED;
307     case FONTSETWIDTH_NORMAL:        return FC_WIDTH_NORMAL;
308     case FONTSETWIDTH_SEMIEXPANDED:  return FC_WIDTH_SEMIEXPANDED;
309     case FONTSETWIDTH_EXPANDED:      return FC_WIDTH_EXPANDED;
310     case FONTSETWIDTH_EXTRAEXPANDED: return FC_WIDTH_EXTRAEXPANDED;
311     case FONTSETWIDTH_ULTRAEXPANDED: return FC_WIDTH_ULTRAEXPANDED;
312     }
313   return FC_WIDTH_NORMAL;
314   }
315 
316 
317 // From fontconfig setwidth to FOX setwidth
fcSetWidth2SetWidth(FXint fcSetWidth)318 static FXint fcSetWidth2SetWidth(FXint fcSetWidth){
319   switch(fcSetWidth){
320     case FC_WIDTH_ULTRACONDENSED:return FONTSETWIDTH_ULTRACONDENSED;
321     case FC_WIDTH_EXTRACONDENSED:return FONTSETWIDTH_EXTRACONDENSED;
322     case FC_WIDTH_CONDENSED:     return FONTSETWIDTH_CONDENSED;
323     case FC_WIDTH_SEMICONDENSED: return FONTSETWIDTH_SEMICONDENSED;
324     case FC_WIDTH_NORMAL:        return FONTSETWIDTH_NORMAL;
325     case FC_WIDTH_SEMIEXPANDED:  return FONTSETWIDTH_SEMIEXPANDED;
326     case FC_WIDTH_EXPANDED:      return FONTSETWIDTH_EXPANDED;
327     case FC_WIDTH_EXTRAEXPANDED: return FONTSETWIDTH_EXTRAEXPANDED;
328     case FC_WIDTH_ULTRAEXPANDED: return FONTSETWIDTH_ULTRAEXPANDED;
329     }
330   return FONTSETWIDTH_NORMAL;
331   }
332 
333 
334 #else
335 
336 // From FOX weight to fontconfig weight
weight2FcWeight(FXint weight)337 static FXint weight2FcWeight(FXint weight){
338   switch(weight){
339     case FONTWEIGHT_THIN:
340     case FONTWEIGHT_EXTRALIGHT:
341     case FONTWEIGHT_LIGHT:     return FC_WEIGHT_LIGHT;
342     case FONTWEIGHT_NORMAL:
343     case FONTWEIGHT_MEDIUM:    return FC_WEIGHT_MEDIUM;
344     case FONTWEIGHT_DEMIBOLD:  return FC_WEIGHT_DEMIBOLD;
345     case FONTWEIGHT_BOLD:      return FC_WEIGHT_BOLD;
346     case FONTWEIGHT_EXTRABOLD:
347     case FONTWEIGHT_HEAVY:     return FC_WEIGHT_BLACK;
348     }
349   return FC_WEIGHT_MEDIUM;
350   }
351 
352 
353 // From fontconfig weight to FOX weight
fcWeight2Weight(FXint fcWeight)354 static FXint fcWeight2Weight(FXint fcWeight){
355   switch(fcWeight){
356     case FC_WEIGHT_LIGHT:     return FONTWEIGHT_LIGHT;
357     case FC_WEIGHT_MEDIUM:    return FONTWEIGHT_MEDIUM;
358     case FC_WEIGHT_DEMIBOLD:  return FONTWEIGHT_DEMIBOLD;
359     case FC_WEIGHT_BOLD:      return FONTWEIGHT_BOLD;
360     case FC_WEIGHT_BLACK:     return FONTWEIGHT_BLACK;
361     }
362   return FONTWEIGHT_NORMAL;
363   }
364 
365 #endif
366 
367 
368 // From FOX slant to fontconfig slant
slant2FcSlant(FXint slant)369 static FXint slant2FcSlant(FXint slant){
370   switch(slant){
371     case FONTSLANT_REGULAR:        return FC_SLANT_ROMAN;
372     case FONTSLANT_ITALIC:         return FC_SLANT_ITALIC;
373     case FONTSLANT_OBLIQUE:        return FC_SLANT_OBLIQUE;
374     case FONTSLANT_REVERSE_ITALIC: return FC_SLANT_ITALIC; // No equivalent FC value
375     case FONTSLANT_REVERSE_OBLIQUE:return FC_SLANT_OBLIQUE;// No equivalent FC value
376     }
377   return FC_SLANT_ROMAN;
378   }
379 
380 
381 // From fontconfig slant to FOX slant
fcSlant2Slant(FXint fcSlant)382 static FXint fcSlant2Slant(FXint fcSlant){
383   switch(fcSlant){
384     case FC_SLANT_ROMAN:  return FONTSLANT_REGULAR;
385     case FC_SLANT_ITALIC: return FONTSLANT_ITALIC;
386     case FC_SLANT_OBLIQUE:return FONTSLANT_OBLIQUE;
387     }
388   return FONTSLANT_REGULAR;
389   }
390 
391 
getDPIXft()392 static double getDPIXft(){
393   double fcDPI;
394   FcPattern* dpiPattern=FcPatternCreate();
395   if(dpiPattern != NULL){
396     FcDefaultSubstitute(dpiPattern);
397     FcPatternGetDouble(dpiPattern, FC_DPI, 0, &fcDPI);
398     FcPatternDestroy(dpiPattern);
399     }
400   return fcDPI;
401   }
402 
403 
getDPIDiffXft()404 static double getDPIDiffXft(){
405   // Perhaps override screen resolution via registry
406   int screenres=FXApp::instance()->reg().readUnsignedEntry("SETTINGS","screenres",100);
407   return screenres/getDPIXft();
408   }
409 
410 
411 // Build fontconfig pattern from face name and hints
buildPatternXft(const FXchar * face,FXuint size,FXuint weight,FXuint slant,FXuint setwidth,FXuint encoding,FXuint hints)412 static FcPattern* buildPatternXft(const FXchar* face,FXuint size,FXuint weight,FXuint slant,FXuint setwidth,FXuint encoding,FXuint hints){
413   FXchar family[104];
414   FXchar foundry[104];
415 
416   // Create pattern object
417   FcPattern* pattern=FcPatternCreate();
418 
419   // Family and foundry name
420   familyandfoundryfromname(family,foundry,face);
421 
422   FXTRACE((150,"family=\"%s\", foundry=\"%s\"\n",family,foundry));
423 
424   // Set family
425   if(strlen(family)>0){
426     FcPatternAddString(pattern,FC_FAMILY,(const FcChar8*)family);
427     }
428 
429   // Set foundry
430   if(strlen(foundry)>0){
431     FcPatternAddString(pattern,FC_FOUNDRY,(const FcChar8*)foundry);
432     }
433 
434   // Set point size
435   if(size>0){
436     FcPatternAddInteger(pattern,FC_SIZE,(int)(size/10*getDPIDiffXft() + 0.5));
437 
438     // Should be 10 but this makes it slightly better;
439     // Suggested by "Niall Douglas" <s_sourceforge@nedprod.com>.
440 //    FcPatternAddDouble(pattern,FC_SIZE,size/7.5);
441 //    FcPatternAddDouble(pattern,FC_SIZE,size/10.0);
442 //  FcPatternAddInteger(pattern,FC_PIXEL_SIZE,size/10);
443     }
444 
445   // Set font weight
446   if(weight!=FONTWEIGHT_DONTCARE){
447     FcPatternAddInteger(pattern,FC_WEIGHT,weight2FcWeight(weight));
448     }
449 
450 #if FC_VERSION >= FCWIDTHVERSION
451   // Set setwidth
452   if(setwidth!=FONTSETWIDTH_DONTCARE){
453     FcPatternAddInteger(pattern,FC_WIDTH,setWidth2FcSetWidth(setwidth));
454     }
455 #endif
456 
457   // Set slant
458   if(slant!=FONTSLANT_DONTCARE){
459     FcPatternAddInteger(pattern,FC_SLANT,slant2FcSlant(slant));
460     }
461 
462   // Set encoding
463   if(encoding!=FONTENCODING_DEFAULT){
464     FcCharSet* charSet=FcCharSetCreate();
465     //encoding2FcCharSet((void*)charSet, (FXFontEncoding)encoding);
466     //FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
467     FcCharSetDestroy(charSet);
468     }
469 
470   // Set pitch
471   if((hints&FONTPITCH_FIXED)!=0){
472     FcPatternAddInteger(pattern,FC_SPACING,FC_MONO);
473     }
474 
475   // Set mono/proportional hint
476   if((hints&FONTPITCH_VARIABLE)!=0){
477     FcPatternAddInteger(pattern,FC_SPACING,FC_PROPORTIONAL);
478     }
479 
480   // Scalable font hint
481   if((hints&FONTHINT_SCALABLE)!=0){
482     FcPatternAddBool(pattern,FC_SCALABLE,TRUE);
483     }
484 
485   //if((hints&FONTHINT_X11) != 0)
486     //FcPatternAddBool(pattern, FC_CORE, TRUE);
487 
488   // Return pattern object
489   return pattern;
490   }
491 
492 
493 // Get font description from pattern
pattern2FontDescXft(FcPattern * p,FXFontDesc * desc)494 static FXbool pattern2FontDescXft(FcPattern* p,FXFontDesc* desc){
495   FXbool res=TRUE;
496   FXString faceFamily,faceFoundry;
497 
498   FcChar8 *family, *foundry;
499   int spacing, setwidth, weight, slant, size;
500   FcBool scalable;
501 
502   if(FcPatternGetString(p,FC_FAMILY,0,&family)==FcResultMatch)
503     faceFamily=(const FXchar*)family;
504   else
505     res = FALSE;
506 
507   if(FcPatternGetString(p, FC_FOUNDRY, 0, &foundry) == FcResultMatch)
508     faceFoundry=(const FXchar*)foundry;
509   else
510     res=FALSE;
511 
512   if(faceFoundry.length()>0){
513     faceFamily.append(" [");
514     faceFamily.append(faceFoundry);
515     faceFamily.append("]");
516     }
517 
518   strncpy(desc->face,faceFamily.text(),sizeof(desc->face)-1);
519 
520 #if FC_VERSION >= FCWIDTHVERSION
521   if(FcPatternGetInteger(p,FC_WIDTH,0,&setwidth)==FcResultMatch){
522     desc->setwidth=fcSetWidth2SetWidth(setwidth);
523     }
524   else{
525     res=FALSE;
526     desc->setwidth=FONTSETWIDTH_NORMAL;
527     }
528 #else
529     desc->setwidth=FONTSETWIDTH_NORMAL;
530 #endif
531 
532   if(FcPatternGetInteger(p, FC_PIXEL_SIZE, 0, &size) == FcResultMatch){
533     desc->size=(int)(size*10/getDPIDiffXft()+0.5);
534     }
535   else{
536     res=FALSE;
537     desc->size=0;
538     }
539 
540   if(FcPatternGetInteger(p,FC_WEIGHT,0,&weight)==FcResultMatch){
541     desc->weight=fcWeight2Weight(weight);
542     }
543   else{
544     res=FALSE;
545     desc->weight=FONTWEIGHT_NORMAL;
546     }
547 
548   if(FcPatternGetInteger(p,FC_SLANT,0,&slant)==FcResultMatch){
549     desc->slant=fcSlant2Slant(slant);
550     }
551   else{
552     res=FALSE;
553     desc->slant=FONTSLANT_REGULAR;
554     }
555 
556   if(FcPatternGetInteger(p,FC_SPACING,0,&spacing)==FcResultMatch){
557     if(spacing==FC_PROPORTIONAL)
558       desc->flags|=FONTPITCH_VARIABLE;
559     else if(spacing==FC_MONO)
560       desc->flags|=FONTPITCH_FIXED;
561     }
562   else{
563     res=FALSE;
564     desc->flags|=FONTPITCH_VARIABLE;
565     }
566 
567   if(FcPatternGetBool(p,FC_SCALABLE,0,&scalable)==FcResultMatch){
568     if(scalable) desc->flags|=FONTHINT_SCALABLE;
569     }
570   else{
571     res=FALSE;
572     }
573 
574   desc->encoding=FONTENCODING_DEFAULT; //FIXME fcEncoding2Encoding(encoding);
575 
576   return res;
577   }
578 
579 
580 
581 #else                                   // Using XLFD
582 
583 
584 
585 // Convert text to font weight
weightfromtext(const FXchar * text)586 static FXuint weightfromtext(const FXchar* text){
587   register FXchar c1=tolower((FXuchar)text[0]);
588   register FXchar c2=tolower((FXuchar)text[1]);
589   if(c1=='l' && c2=='i') return FONTWEIGHT_LIGHT;
590   if(c1=='n' && c2=='o') return FONTWEIGHT_NORMAL;
591   if(c1=='r' && c2=='e') return FONTWEIGHT_REGULAR;
592   if(c1=='m' && c2=='e') return FONTWEIGHT_MEDIUM;
593   if(c1=='d' && c2=='e') return FONTWEIGHT_DEMIBOLD;
594   if(c1=='b' && c2=='o') return FONTWEIGHT_BOLD;
595   if(c1=='b' && c2=='l') return FONTWEIGHT_BLACK;
596   return FONTWEIGHT_DONTCARE;
597   }
598 
599 
600 // Convert text to slant
slantfromtext(const FXchar * text)601 static FXuint slantfromtext(const FXchar* text){
602   register FXchar c1=tolower((FXuchar)text[0]);
603   register FXchar c2=tolower((FXuchar)text[1]);
604   if(c1=='i') return FONTSLANT_ITALIC;
605   if(c1=='o') return FONTSLANT_OBLIQUE;
606   if(c1=='r' && c2=='i') return FONTSLANT_REVERSE_ITALIC;
607   if(c1=='r' && c2=='o') return FONTSLANT_REVERSE_OBLIQUE;
608   if(c1=='r') return FONTSLANT_REGULAR;
609   return FONTSLANT_DONTCARE;
610   }
611 
612 
613 // Convert text to setwidth
setwidthfromtext(const FXchar * text)614 static FXuint setwidthfromtext(const FXchar* text){
615   if(text[0]=='m') return FONTSETWIDTH_MEDIUM;
616   if(text[0]=='w') return FONTSETWIDTH_EXTRAEXPANDED;
617   if(text[0]=='r') return FONTSETWIDTH_MEDIUM;
618   if(text[0]=='c') return FONTSETWIDTH_CONDENSED;
619   if(text[0]=='n'){
620     if(text[1]=='a') return FONTSETWIDTH_CONDENSED;
621     if(text[1]=='o') return FONTSETWIDTH_MEDIUM;
622     return FONTSETWIDTH_DONTCARE;
623     }
624   if(text[0]=='e' && text[1]=='x' && text[2]=='p') return FONTSETWIDTH_EXPANDED;
625   if(text[0]=='e' && text[1]=='x' && text[2]=='t' && text[3]=='r' && text[4]=='a'){
626     if(text[5]=='c') return FONTSETWIDTH_EXTRACONDENSED;
627     if(text[5]=='e') return FONTSETWIDTH_EXTRAEXPANDED;
628     return FONTSETWIDTH_DONTCARE;
629     }
630   if(text[0]=='u' && text[1]=='l' && text[2]=='t' && text[3]=='r' && text[4]=='a'){
631     if(text[5]=='c') return FONTSETWIDTH_ULTRACONDENSED;
632     if(text[5]=='e') return FONTSETWIDTH_ULTRAEXPANDED;
633     return FONTSETWIDTH_DONTCARE;
634     }
635   if((text[0]=='s' || text[0]=='d') && text[1]=='e' && text[2]=='m' && text[3]=='i'){
636     if(text[5]=='c') return FONTSETWIDTH_SEMICONDENSED;
637     if(text[5]=='e') return FONTSETWIDTH_SEMIEXPANDED;
638     return FONTSETWIDTH_DONTCARE;
639     }
640   return FONTSETWIDTH_DONTCARE;
641   }
642 
643 
644 // Convert pitch to flags
pitchfromtext(const FXchar * text)645 static FXuint pitchfromtext(const FXchar* text){
646   register FXchar c=tolower((FXuchar)text[0]);
647   if(c=='p') return FONTPITCH_VARIABLE;
648   if(c=='m' || c=='c') return FONTPITCH_FIXED;
649   return FONTPITCH_DEFAULT;
650   }
651 
652 
653 // Test if font is ISO8859
isISO8859(const FXchar * text)654 static FXbool isISO8859(const FXchar* text){
655   return tolower((FXuchar)text[0])=='i' && tolower((FXuchar)text[1])=='s' && tolower((FXuchar)text[2])=='o' && text[3]=='8' && text[4]=='8' && text[5]=='5' && text[6]=='9';
656   }
657 
658 
659 // Test if font is KOI8
isKOI8(const FXchar * text)660 static FXbool isKOI8(const FXchar* text){
661   return tolower((FXuchar)text[0])=='k' && tolower((FXuchar)text[1])=='o' && tolower((FXuchar)text[2])=='i' && text[3]=='8';
662   }
663 
664 // Test if font is microsoft cpXXXX
isMSCP(const FXchar * text)665 static FXbool isMSCP(const FXchar* text){
666   return tolower((FXuchar)text[0])=='m' && tolower((FXuchar)text[1])=='i' && tolower((FXuchar)text[2])=='c' && tolower((FXuchar)text[3])=='r' && tolower((FXuchar)text[4])=='o' && tolower((FXuchar)text[5])=='s' && tolower((FXuchar)text[6])=='o' && tolower((FXuchar)text[7])=='f' && tolower((FXuchar)text[8])=='t';
667   }
668 
669 
670 // Test if font is multi-byte
ismultibyte(const FXchar * text)671 static FXbool ismultibyte(const FXchar* text){
672 
673   // Unicode font; not yet ...
674   if(tolower((FXuchar)text[0])=='i' && tolower((FXuchar)text[1])=='s' && tolower((FXuchar)text[2])=='o' && text[3]=='6' && text[4]=='4' && text[5]=='6') return TRUE;
675 
676   // Japanese font
677   if(tolower((FXuchar)text[0])=='j' && tolower((FXuchar)text[1])=='i' && tolower((FXuchar)text[2])=='s' && text[3]=='x') return TRUE;
678 
679   // Chinese font
680   if(tolower((FXuchar)text[0])=='g' && tolower((FXuchar)text[1])=='b') return TRUE;
681 
682   // Another type of chinese font
683   if(tolower((FXuchar)text[0])=='b' && tolower((FXuchar)text[1])=='i' && tolower((FXuchar)text[2])=='g' && text[3]=='5') return TRUE;
684 
685   // Korean
686   if(tolower((FXuchar)text[0])=='k' && tolower((FXuchar)text[1])=='s' && tolower((FXuchar)text[2])=='c') return TRUE;
687 
688   return FALSE;
689   }
690 
691 
692 // Encoding from xlfd-registry and xlfd-encoding
encodingfromxlfd(const FXchar * registry,const FXchar * encoding)693 static FXuint encodingfromxlfd(const FXchar* registry,const FXchar* encoding){
694   if(isISO8859(registry)){
695     return FONTENCODING_ISO_8859_1+atoi(encoding)-1;
696     }
697   if(isKOI8(registry)){
698     if(encoding[0]=='u' || encoding[0]=='U'){
699       return FONTENCODING_KOI8_U;
700       }
701     if(encoding[0]=='r' || encoding[0]=='R'){
702       return FONTENCODING_KOI8_R;
703       }
704     return FONTENCODING_KOI8;
705     }
706   if(isMSCP(registry)){
707     if((encoding[0]=='c' || encoding[0]=='C') && (encoding[1]=='p' || encoding[1]=='P')){
708       return atoi(encoding+2);
709       }
710     }
711   return FONTENCODING_DEFAULT;
712   }
713 
714 
715 // Get list of font names matching pattern
listfontnames(Display * dpy,const char * pattern,int & numfnames)716 static char **listfontnames(Display* dpy,const char* pattern,int& numfnames){
717   int maxfnames=1024;
718   char **fnames;
719   for(;;){
720     fnames=XListFonts(dpy,pattern,maxfnames,&numfnames);
721     if((fnames==NULL) || (numfnames<maxfnames)) break;
722     XFreeFontNames(fnames);
723     maxfnames<<=1;
724     }
725   return fnames;
726   }
727 
728 
729 // Return number of fonts matching name
matchingfonts(Display * dpy,const char * pattern)730 static int matchingfonts(Display* dpy,const char* pattern){
731   char **fnames; int numfnames;
732   fnames=listfontnames(dpy,pattern,numfnames);
733   XFreeFontNames(fnames);
734   if(numfnames>0) FXTRACE((100,"matched: %s\n",pattern));
735   return numfnames;
736   }
737 
738 
739 // Parse font name into parts
parsefontname(char ** fields,char * fontname)740 static int parsefontname(char** fields,char* fontname){
741   register char** end=fields+XLFD_ENCODING;
742   register char** beg=fields;
743   register char*  ptr=fontname;
744   if(*ptr++ == '-'){
745     while(1){
746       *beg++=ptr;
747       if(beg>end) return 1;
748       while(*ptr!='-'){
749         if(*ptr=='\0') return 0;
750         ptr++;
751         }
752       *ptr++='\0';
753       }
754     }
755   return 0;
756   }
757 
758 
759 // Try find matching font
findmatch(char * fontname,const char * forge,const char * family)760 char* FXFont::findmatch(char* fontname,const char* forge,const char* family){
761   FXchar candidate[MAX_XLFD],*field[14],**fnames;
762   FXuint size,weight,slant,setwidth,encoding,pitch;
763   FXint bestf,bestdweight,bestdsize,bestvalue,bestscalable,bestxres,bestyres;
764   FXint screenres,xres,yres;
765   FXint dweight,scalable,dsize;
766   FXint numfnames,f,value;
767 
768   // Get fonts matching the pattern
769   sprintf(candidate,"-%s-%s-*-*-*-*-*-*-*-*-*-*-*-*",forge,family);
770   fnames=listfontnames(DISPLAY(getApp()),candidate,numfnames);
771   if(!fnames) return NULL;
772 
773   // Init match values
774   bestf=-1;
775   bestvalue=0;
776 
777   bestdsize=10000000;
778   bestdweight=10000000;
779   bestscalable=0;
780   bestxres=75;
781   bestyres=75;
782 
783   // Perhaps override screen resolution via registry
784   screenres=getApp()->reg().readUnsignedEntry("SETTINGS","screenres",100);
785 
786   // Validate
787   if(screenres<50) screenres=50;
788   if(screenres>200) screenres=200;
789 
790   FXTRACE((150,"Matching Fonts for screenres=%d :\n",screenres));
791 
792   // Loop over all fonts to find the best match
793   for(f=0; f<numfnames; f++){
794     strncpy(candidate,fnames[f],MAX_XLFD);
795     if(parsefontname(field,candidate)){
796 
797       // This font's match value
798       value=0;
799       scalable=0;
800       dsize=1000000;
801       dweight=1000;
802 
803       // Match encoding
804       encoding=encodingfromxlfd(field[XLFD_REGISTRY],field[XLFD_ENCODING]);
805       if(wantedEncoding==FONTENCODING_DEFAULT){
806         if(encoding==FONTENCODING_ISO_8859_1) value+=ENCODING_FACTOR;
807         }
808       else{
809         if(encoding==wantedEncoding) value+=ENCODING_FACTOR;
810         }
811 
812       // Match pitch
813       pitch=pitchfromtext(field[XLFD_SPACING]);
814       if(hints&FONTPITCH_FIXED){
815         if(pitch&FONTPITCH_FIXED) value+=PITCH_FACTOR;
816         }
817       else if(hints&FONTPITCH_VARIABLE){
818         if(pitch&FONTPITCH_VARIABLE) value+=PITCH_FACTOR;
819         }
820 
821       // Scalable
822       if(EQUAL1(field[XLFD_PIXELSIZE],'0') && EQUAL1(field[XLFD_POINTSIZE],'0') && EQUAL1(field[XLFD_AVERAGE],'0')){
823         value+=SCALABLE_FACTOR;
824         scalable=1;
825         }
826       else{
827         if(!(hints&FONTHINT_SCALABLE)) value+=SCALABLE_FACTOR;
828         }
829 
830       // Polymorphic
831       if(EQUAL1(field[XLFD_WEIGHT],'0') || EQUAL1(field[XLFD_SETWIDTH],'0') || EQUAL1(field[XLFD_SLANT],'0') || EQUAL1(field[XLFD_ADDSTYLE],'0')){
832         value+=POLY_FACTOR;
833         }
834       else{
835         if(!(hints&FONTHINT_POLYMORPHIC)) value+=POLY_FACTOR;
836         }
837 
838       // Prefer normal weight
839       weight=weightfromtext(field[XLFD_WEIGHT]);
840       if(wantedWeight==FONTWEIGHT_DONTCARE){
841         dweight=weight-FONTWEIGHT_NORMAL;
842         dweight=FXABS(dweight);
843         }
844       else{
845         dweight=weight-wantedWeight;
846         dweight=FXABS(dweight);
847         }
848 
849       // Prefer normal slant
850       slant=slantfromtext(field[XLFD_SLANT]);
851       if(wantedSlant==FONTSLANT_DONTCARE){
852         if(slant==FONTSLANT_REGULAR) value+=SLANT_FACTOR;
853         }
854       else{
855         if(slant==wantedSlant) value+=SLANT_FACTOR;
856         }
857 
858       // Prefer unexpanded and uncompressed
859       setwidth=setwidthfromtext(field[XLFD_SETWIDTH]);
860       if(wantedSetwidth==FONTSETWIDTH_DONTCARE){
861         if(setwidth==FONTSETWIDTH_NORMAL) value+=SETWIDTH_FACTOR;
862         }
863       else{
864         if(setwidth==wantedSetwidth) value+=SETWIDTH_FACTOR;
865         }
866 
867       // The font can be rendered at any resolution, so render at actual device resolution
868       if(EQUAL1(field[XLFD_RESOLUTION_X],'0') && EQUAL1(field[XLFD_RESOLUTION_Y],'0')){
869         xres=screenres;
870         yres=screenres;
871         }
872 
873       // Else get the resolution for which the font is designed
874       else{
875         xres=atoi(field[XLFD_RESOLUTION_X]);
876         yres=atoi(field[XLFD_RESOLUTION_Y]);
877         }
878 
879       // If scalable, we can of course get the exact size we want
880       // We do not set dsize to 0, as we prefer a bitmapped font that gets within
881       // 10% over a scalable one that's exact, as the bitmapped fonts look much better
882       // at small sizes than scalable ones...
883       if(scalable){
884         value+=SIZE_FACTOR;
885         dsize=wantedSize/10;
886         size=wantedSize;
887         }
888 
889       // Otherwise, we try to get something close
890       else{
891 
892         // We correct for the actual screen resolution; if the font is rendered at a
893         // 100 dpi, and we have a screen with 90dpi, the actual point size of the font
894         // should be multiplied by (100/90).
895         size=(yres*atoi(field[XLFD_POINTSIZE]))/screenres;
896 
897         // We strongly prefer the largest pointsize not larger than the desired pointsize
898         if(size<=wantedSize){
899           value+=SIZE_FACTOR;
900           dsize=wantedSize-size;
901           }
902 
903         // But if we can't get that, we'll take anything thats close...
904         else{
905           dsize=size-wantedSize;
906           }
907         }
908 
909       FXTRACE((160,"%4d: match=%-3x dw=%-3d ds=%3d sc=%d xres=%-3d yres=%-3d xlfd=\"%s\"\n",f,value,dweight,dsize,scalable,xres,yres,fnames[f]));
910 
911       // How close is the match?
912       if((value>bestvalue) || ((value==bestvalue) && (dsize<bestdsize)) || ((value==bestvalue) && (dsize==bestdsize) && (dweight<bestdweight))){
913         bestvalue=value;
914         actualName=field[XLFD_FAMILY];
915         actualName.append(" [");
916         actualName.append(field[XLFD_FOUNDRY]);
917         actualName.append("]");
918         actualSize=size;
919         actualWeight=weight;
920         actualSlant=slant;
921         actualSetwidth=setwidth;
922         actualEncoding=encoding;
923         bestdsize=dsize;
924         bestdweight=dweight;
925         bestscalable=scalable;
926         bestxres=xres;
927         bestyres=yres;
928         bestf=f;
929         }
930       }
931     }
932 
933   // Got one
934   if(0<=bestf){
935     if(!bestscalable){
936       strncpy(fontname,fnames[bestf],MAX_XLFD);
937       }
938     else{
939       strncpy(candidate,fnames[bestf],MAX_XLFD);
940       parsefontname(field,candidate);
941 
942       // Build XLFD, correcting for possible difference between font resolution and screen resolution
943       sprintf(fontname,"-%s-%s-%s-%s-%s-%s-*-%d-%d-%d-%s-*-%s-%s",field[XLFD_FOUNDRY],field[XLFD_FAMILY],field[XLFD_WEIGHT],field[XLFD_SLANT],field[XLFD_SETWIDTH],field[XLFD_ADDSTYLE],(bestyres*wantedSize)/screenres,bestxres,bestyres,field[XLFD_SPACING],field[XLFD_REGISTRY],field[XLFD_ENCODING]);
944 
945       // This works!! draw text sideways:- but need to get some more experience with this
946       //sprintf(fontname,"-%s-%s-%s-%s-%s-%s-*-[0 64 ~64 0]-%d-%d-%s-*-%s-%s",field[XLFD_FOUNDRY],field[XLFD_FAMILY],field[XLFD_WEIGHT],field[XLFD_SLANT],field[XLFD_SETWIDTH],field[XLFD_ADDSTYLE],screenxres,screenyres,field[XLFD_SPACING],field[XLFD_REGISTRY],field[XLFD_ENCODING]);
947       }
948     FXTRACE((150,"Best Font:\n"));
949     FXTRACE((150,"%4d: match=%3x dw=%-3d ds=%-3d sc=%d xres=%-3d yres=%-3d xlfd=\"%s\"\n",bestf,bestvalue,bestdweight,bestdsize,bestscalable,bestxres,bestyres,fontname));
950 
951     // Free fonts
952     XFreeFontNames(fnames);
953     return fontname;
954     }
955 
956   // Free fonts
957   XFreeFontNames(fnames);
958   return NULL;
959   }
960 
961 
962 // Try load the best matching font
findbestfont(char * fontname)963 const char* FXFont::findbestfont(char *fontname){
964   register const FXchar *altfoundry;
965   register const FXchar *altfamily;
966   FXchar family[104];
967   FXchar foundry[104];
968 
969   // Family and foundry name
970   familyandfoundryfromname(family,foundry,wantedName.text());
971 
972   // Try match with specified family and foundry
973   if(family[0]){
974     altfamily=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",family,family);
975     if(foundry[0]){
976       altfoundry=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",foundry,foundry);
977       if(findmatch(fontname,altfoundry,altfamily)) return fontname;
978       }
979     if(findmatch(fontname,"*",altfamily)) return fontname;
980     }
981 
982   // Try swiss if we didn't have a match yet
983   if((hints&(FONTHINT_SWISS|FONTHINT_SYSTEM) || !(hints&FONTHINT_MASK))){
984     altfamily=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","helvetica","helvetica");
985     if(findmatch(fontname,"*",altfamily)) return fontname;
986     }
987 
988   // Try roman if we didn't have a match yet
989   if((hints&FONTHINT_ROMAN) || !(hints&FONTHINT_MASK)){
990     altfamily=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","times","times");
991     if(findmatch(fontname,"*",altfamily)) return fontname;
992     }
993 
994   // Try modern if we didn't have a match yet
995   if((hints&FONTHINT_MODERN) || !(hints&FONTHINT_MASK)){
996     altfamily=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","courier","courier");
997     if(findmatch(fontname,"*",altfamily)) return fontname;
998     }
999 
1000   // Try decorative if we didn't have a match yet
1001   if((hints&FONTHINT_DECORATIVE) || !(hints&FONTHINT_MASK)){
1002     altfamily=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","gothic","gothic");
1003     if(findmatch(fontname,"*",altfamily)) return fontname;
1004     }
1005 
1006   // Try anything
1007   if(findmatch(fontname,"*","*")) return fontname;
1008 
1009   // Fail
1010   return "";
1011   }
1012 
1013 
1014 // Try these fallbacks for swiss hint
1015 const char* swissfallback[]={
1016   "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-*-*",
1017   "-*-lucida-bold-r-*-*-*-120-*-*-*-*-*-*",
1018   "-*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
1019   "-*-lucida-medium-r-*-*-*-120-*-*-*-*-*-*",
1020   "-*-helvetica-*-*-*-*-*-120-*-*-*-*-*-*",
1021   "-*-lucida-*-*-*-*-*-120-*-*-*-*-*-*",
1022   NULL
1023   };
1024 
1025 
1026 // Try these fallbacks for times hint
1027 const char* romanfallback[]={
1028   "-*-times-bold-r-*-*-*-120-*-*-*-*-*-*",
1029   "-*-charter-bold-r-*-*-*-120-*-*-*-*-*-*",
1030   "-*-times-medium-r-*-*-*-120-*-*-*-*-*-*",
1031   "-*-charter-medium-r-*-*-*-120-*-*-*-*-*-*",
1032   "-*-times-*-*-*-*-*-120-*-*-*-*-*-*",
1033   "-*-charter-*-*-*-*-*-120-*-*-*-*-*-*",
1034   NULL
1035   };
1036 
1037 
1038 // Try these fallbacks for modern hint
1039 const char* modernfallback[]={
1040   "-*-courier-bold-r-*-*-*-120-*-*-*-*-*-*",
1041   "-*-lucidatypewriter-bold-r-*-*-*-120-*-*-*-*-*-*",
1042   "-*-courier-medium-r-*-*-*-120-*-*-*-*-*-*",
1043   "-*-lucidatypewriter-medium-r-*-*-*-120-*-*-*-*-*-*",
1044   "-*-courier-*-*-*-*-*-120-*-*-*-*-*-*",
1045   "-*-lucidatypewriter-*-*-*-*-*-120-*-*-*-*-*-*",
1046   NULL
1047   };
1048 
1049 
1050 // Try these final fallbacks
1051 const char* finalfallback[]={
1052   "7x13",
1053   "8x13",
1054   "7x14",
1055   "8x16",
1056   "9x15",
1057   NULL
1058   };
1059 
1060 
1061 // See which fallback font exists
fallbackfont(Display * dpy,FXuint hints)1062 static const char* fallbackfont(Display *dpy,FXuint hints){
1063   register const char *fname;
1064   register int i;
1065 
1066   // Try swiss if we wanted swiss, or if we don't care
1067   if((hints&FONTHINT_SWISS) || !(hints&FONTHINT_MASK)){
1068     for(i=0; (fname=swissfallback[i])!=NULL; i++){
1069       if(matchingfonts(dpy,fname)>0) return fname;
1070       }
1071     }
1072 
1073   // Try roman if we wanted roman, or if we don't care
1074   if((hints&FONTHINT_ROMAN) || !(hints&FONTHINT_MASK)){
1075     for(i=0; (fname=romanfallback[i])!=NULL; i++){
1076       if(matchingfonts(dpy,fname)>0) return fname;
1077       }
1078     }
1079 
1080   // Try modern if we wanted modern, or if we don't care
1081   if((hints&FONTHINT_MODERN) || !(hints&FONTHINT_MASK)){
1082     for(i=0; (fname=modernfallback[i])!=NULL; i++){
1083       if(matchingfonts(dpy,fname)>0) return fname;
1084       }
1085     }
1086 
1087   // Try final fallback fonts
1088   for(i=0; (fname=finalfallback[i])!=NULL; i++){
1089     if(matchingfonts(dpy,fname)>0) return fname;
1090     }
1091 
1092   // This one has to be there
1093   return "fixed";
1094   }
1095 
1096 #endif
1097 
1098 
1099 /*******************************************************************************/
1100 
1101 // Helper functions WIN32
1102 
1103 #else
1104 
1105 
1106 // Character set encoding
FXFontEncoding2CharSet(FXuint encoding)1107 static BYTE FXFontEncoding2CharSet(FXuint encoding){
1108   switch(encoding){
1109     case FONTENCODING_DEFAULT: return DEFAULT_CHARSET;
1110     case FONTENCODING_TURKISH: return TURKISH_CHARSET;
1111     case FONTENCODING_BALTIC: return BALTIC_CHARSET;
1112     case FONTENCODING_CYRILLIC: return RUSSIAN_CHARSET;
1113     case FONTENCODING_ARABIC: return ARABIC_CHARSET;
1114     case FONTENCODING_GREEK: return GREEK_CHARSET;
1115     case FONTENCODING_HEBREW: return HEBREW_CHARSET;
1116     case FONTENCODING_THAI: return THAI_CHARSET;
1117     case FONTENCODING_EASTEUROPE: return EASTEUROPE_CHARSET;
1118     case FONTENCODING_USASCII: return ANSI_CHARSET;
1119     }
1120   return DEFAULT_CHARSET;
1121   }
1122 
1123 
1124 // Character set encoding
CharSet2FXFontEncoding(BYTE lfCharSet)1125 static FXuint CharSet2FXFontEncoding(BYTE lfCharSet){
1126   switch(lfCharSet){
1127     case ANSI_CHARSET: return FONTENCODING_USASCII;
1128     case ARABIC_CHARSET: return FONTENCODING_ARABIC;
1129     case BALTIC_CHARSET: return FONTENCODING_BALTIC;
1130     case CHINESEBIG5_CHARSET: return FONTENCODING_DEFAULT;
1131     case DEFAULT_CHARSET: return FONTENCODING_DEFAULT;
1132     case EASTEUROPE_CHARSET: return FONTENCODING_EASTEUROPE;
1133     case GB2312_CHARSET: return FONTENCODING_DEFAULT;
1134     case GREEK_CHARSET: return FONTENCODING_GREEK;
1135 #if !defined (__WATCOMC__)
1136     case HANGUL_CHARSET: return FONTENCODING_DEFAULT;
1137 #endif
1138     case HEBREW_CHARSET: return FONTENCODING_HEBREW;
1139     case MAC_CHARSET: return FONTENCODING_DEFAULT;
1140     case OEM_CHARSET: return FONTENCODING_DEFAULT;
1141     case SYMBOL_CHARSET: return FONTENCODING_DEFAULT;
1142     case RUSSIAN_CHARSET: return FONTENCODING_CYRILLIC;
1143     case SHIFTJIS_CHARSET: return FONTENCODING_DEFAULT;
1144     case THAI_CHARSET: return FONTENCODING_THAI;
1145     case TURKISH_CHARSET: return FONTENCODING_TURKISH;
1146     }
1147   return FONTENCODING_DEFAULT;
1148   }
1149 
1150 
1151 // Yuk. Need to get some data into the callback function.
1152 struct FXFontStore {
1153   HDC         hdc;
1154   FXFontDesc *fonts;
1155   FXuint      numfonts;
1156   FXuint      size;
1157   FXFontDesc  desc;
1158   };
1159 
1160 
1161 // Callback function for EnumFontFamiliesEx()
EnumFontFamExProc(const LOGFONT * lf,const TEXTMETRIC * lptm,DWORD FontType,LPARAM lParam)1162 static int CALLBACK EnumFontFamExProc(const LOGFONT *lf,const TEXTMETRIC *lptm,DWORD FontType,LPARAM lParam){
1163   register FXFontStore *pFontStore=(FXFontStore*)lParam;
1164   FXASSERT(lf);
1165   FXASSERT(lptm);
1166   FXASSERT(pFontStore);
1167 
1168   // Get pitch
1169   FXuint flags=FONTPITCH_DEFAULT;
1170   if(lf->lfPitchAndFamily&FIXED_PITCH) flags|=FONTPITCH_FIXED;
1171   if(lf->lfPitchAndFamily&VARIABLE_PITCH) flags|=FONTPITCH_VARIABLE;
1172 
1173   // Get hints
1174   if(lf->lfPitchAndFamily&FF_DONTCARE) flags|=FONTHINT_DONTCARE;
1175   if(lf->lfPitchAndFamily&FF_MODERN) flags|=FONTHINT_MODERN;
1176   if(lf->lfPitchAndFamily&FF_ROMAN) flags|=FONTHINT_ROMAN;
1177   if(lf->lfPitchAndFamily&FF_SCRIPT) flags|=FONTHINT_SCRIPT;
1178   if(lf->lfPitchAndFamily&FF_DECORATIVE) flags|=FONTHINT_DECORATIVE;
1179   if(lf->lfPitchAndFamily&FF_SWISS) flags|=FONTHINT_SWISS;
1180 
1181   // Skip if no match
1182   FXuint h=pFontStore->desc.flags;
1183   if((h&FONTPITCH_FIXED) && !(flags&FONTPITCH_FIXED)) return 1;
1184   if((h&FONTPITCH_VARIABLE) && !(flags&FONTPITCH_VARIABLE)) return 1;
1185 
1186   // Get weight (also guess from the name)
1187   FXuint weight=lf->lfWeight;
1188   if(strstr(lf->lfFaceName,"Bold")!=NULL) weight=FONTWEIGHT_BOLD;
1189   if(strstr(lf->lfFaceName,"Black")!=NULL) weight=FONTWEIGHT_BLACK;
1190   if(strstr(lf->lfFaceName,"Demi")!=NULL) weight=FONTWEIGHT_DEMIBOLD;
1191   if(strstr(lf->lfFaceName,"Light")!=NULL) weight=FONTWEIGHT_LIGHT;
1192   if(strstr(lf->lfFaceName,"Medium")!=NULL) weight=FONTWEIGHT_MEDIUM;
1193 
1194   // Skip if weight doesn't match
1195   FXuint wt=pFontStore->desc.weight;
1196   if((wt!=FONTWEIGHT_DONTCARE) && (wt!=weight)) return 1;
1197 
1198   // Get slant
1199   FXuint slant=FONTSLANT_REGULAR;
1200   if(lf->lfItalic==TRUE) slant=FONTSLANT_ITALIC;
1201   if(strstr(lf->lfFaceName,"Italic")!=NULL) slant=FONTSLANT_ITALIC;
1202   if(strstr(lf->lfFaceName,"Roman")!=NULL) slant=FONTSLANT_REGULAR;
1203 
1204   // Skip if no match
1205   FXuint sl=pFontStore->desc.slant;
1206   if((sl!=FONTSLANT_DONTCARE) && (sl!=slant)) return 1;
1207 
1208   // Get set width (also guess from the name)
1209   FXuint setwidth=FONTSETWIDTH_DONTCARE;
1210   if(strstr(lf->lfFaceName,"Cond")!=NULL) setwidth=FONTSETWIDTH_CONDENSED;
1211   if(strstr(lf->lfFaceName,"Narrow")!=NULL) setwidth=FONTSETWIDTH_NARROW;
1212   if(strstr(lf->lfFaceName,"Ext Cond")!=NULL) setwidth=FONTSETWIDTH_EXTRACONDENSED;
1213 
1214   // Skip if no match
1215   FXuint sw=pFontStore->desc.setwidth;
1216   if((sw!=FONTSETWIDTH_DONTCARE) && (sw!=setwidth)) return 1;
1217 
1218   // Get encoding
1219   FXuint encoding=CharSet2FXFontEncoding(lf->lfCharSet);
1220 
1221   // Skip if no match
1222   FXuint en=pFontStore->desc.encoding;
1223   if((en!=FONTENCODING_DEFAULT) && (en!=encoding)) return 1;
1224 
1225   // Is it scalable?
1226   if(FontType==TRUETYPE_FONTTYPE){
1227     flags|=FONTHINT_SCALABLE;
1228     }
1229 
1230   // Is it polymorphic?
1231   if(FontType==TRUETYPE_FONTTYPE){
1232     flags|=FONTHINT_POLYMORPHIC;
1233     }
1234 
1235   // Initial allocation of storage?
1236   if(pFontStore->numfonts==0){
1237     FXMALLOC(&pFontStore->fonts,FXFontDesc,50);
1238     if(pFontStore->fonts==0) return 0;
1239     pFontStore->size=50;
1240     }
1241 
1242   // Grow the array if needed
1243   if(pFontStore->numfonts>=pFontStore->size){
1244     FXRESIZE(&pFontStore->fonts,FXFontDesc,pFontStore->size+50);
1245     if(pFontStore->fonts==0) return 0;
1246     pFontStore->size+=50;
1247     }
1248 
1249   FXFontDesc *fonts=pFontStore->fonts;
1250   FXuint numfonts=pFontStore->numfonts;
1251 
1252   strncpy(fonts[numfonts].face,lf->lfFaceName,sizeof(fonts[0].face));
1253   if(lf->lfHeight<0){
1254     fonts[numfonts].size=-MulDiv(lf->lfHeight,720,GetDeviceCaps(pFontStore->hdc,LOGPIXELSY));
1255     }
1256   else{
1257     fonts[numfonts].size=MulDiv(lf->lfHeight,720,GetDeviceCaps(pFontStore->hdc,LOGPIXELSY));
1258     }
1259   fonts[numfonts].weight=weight;
1260   fonts[numfonts].slant=slant;
1261   fonts[numfonts].encoding=encoding;
1262   fonts[numfonts].setwidth=setwidth;
1263   fonts[numfonts].flags=flags;
1264 
1265   pFontStore->fonts=fonts;
1266   pFontStore->numfonts++;
1267 
1268   // Must return 1 to continue enumerating fonts
1269   return 1;
1270   }
1271 
1272 
1273 
1274 #endif
1275 
1276 
1277 /*******************************************************************************/
1278 
1279 // Object implementation
1280 FXIMPLEMENT(FXFont,FXId,NULL,0)
1281 
1282 
1283 // Deserialization
FXFont()1284 FXFont::FXFont(){
1285   wantedSize=0;
1286   actualSize=0;
1287   wantedWeight=0;
1288   actualWeight=0;
1289   wantedSlant=0;
1290   actualSlant=0;
1291   wantedSetwidth=0;
1292   actualSetwidth=0;
1293   wantedEncoding=0;
1294   actualEncoding=0;
1295   hints=0;
1296   font=NULL;
1297 #ifdef WIN32
1298   dc=NULL;
1299 #endif
1300   }
1301 
1302 
1303 // Construct font from given font description
FXFont(FXApp * a,const FXString & string)1304 FXFont::FXFont(FXApp* a,const FXString& string):FXId(a){
1305   FXTRACE((100,"FXFont::FXFont %p\n",this));
1306   wantedSize=0;
1307   actualSize=0;
1308   wantedWeight=0;
1309   actualWeight=0;
1310   wantedSlant=0;
1311   actualSlant=0;
1312   wantedSetwidth=0;
1313   actualSetwidth=0;
1314   wantedEncoding=0;
1315   actualEncoding=0;
1316   hints=0;
1317   font=NULL;
1318 #ifdef WIN32
1319   dc=NULL;
1320 #endif
1321   setFont(string);
1322   }
1323 
1324 
1325 // Construct a font with given family name, size in points(pixels), weight, slant, character set encoding, setwidth, and hints
FXFont(FXApp * a,const FXString & face,FXuint sz,FXuint wt,FXuint sl,FXuint enc,FXuint setw,FXuint h)1326 FXFont::FXFont(FXApp* a,const FXString& face,FXuint sz,FXuint wt,FXuint sl,FXuint enc,FXuint setw,FXuint h):FXId(a),wantedName(face){
1327   FXTRACE((100,"FXFont::FXFont %p\n",this));
1328   wantedSize=10*sz;
1329   wantedWeight=wt;
1330   wantedSlant=sl;
1331   wantedSetwidth=setw;
1332   wantedEncoding=enc;
1333   actualSize=0;
1334   actualWeight=0;
1335   actualSlant=0;
1336   actualSetwidth=0;
1337   actualEncoding=0;
1338   hints=(h&~FONTHINT_X11);          // System-independent method
1339   font=NULL;
1340 #ifdef WIN32
1341   dc=NULL;
1342 #endif
1343   }
1344 
1345 
1346 // Construct font from font description
FXFont(FXApp * a,const FXFontDesc & fontdesc)1347 FXFont::FXFont(FXApp* a,const FXFontDesc& fontdesc):FXId(a),wantedName(fontdesc.face){
1348   FXTRACE((100,"FXFont::FXFont %p\n",this));
1349   wantedSize=fontdesc.size;
1350   wantedWeight=fontdesc.weight;
1351   wantedSlant=fontdesc.slant;
1352   wantedSetwidth=fontdesc.setwidth;
1353   wantedEncoding=fontdesc.encoding;
1354   actualSize=0;
1355   actualWeight=0;
1356   actualSlant=0;
1357   actualSetwidth=0;
1358   actualEncoding=0;
1359   hints=fontdesc.flags;
1360   font=NULL;
1361 #ifdef WIN32
1362   dc=NULL;
1363 #endif
1364   }
1365 
1366 
1367 /*******************************************************************************/
1368 
1369 
1370 // Create font
create()1371 void FXFont::create(){
1372   if(!xid){
1373     if(getApp()->isInitialized()){
1374       FXTRACE((100,"%s::create %p\n",getClassName(),this));
1375 #ifndef WIN32
1376 
1377 #ifdef HAVE_XFT_H                       // Using XFT
1378       FcPattern *pattern,*p;
1379       FcResult result;
1380 
1381       FXTRACE((150,"%s::create: Xft font=\"%s\"\n",getClassName(),wantedName.text()));
1382 
1383       // Build pattern
1384       pattern=buildPatternXft(wantedName.text(),wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints);
1385 
1386       // Pattern substitutions
1387       FcConfigSubstitute(0,pattern,FcMatchPattern);
1388       FcDefaultSubstitute(pattern);
1389 
1390       // Find pattern matching a font
1391       p=FcFontMatch(0,pattern,&result);
1392 
1393       // Get back the matched font properties
1394       FXFontDesc desc;
1395       pattern2FontDescXft(p, &desc);
1396       actualName = desc.face;
1397       actualSize = desc.size;
1398       actualWeight = desc.weight;
1399       actualSlant = desc.slant;
1400       actualSetwidth = desc.setwidth;
1401       actualEncoding = desc.encoding;
1402 
1403       // Create font
1404       font=XftFontOpenPattern(DISPLAY(getApp()),p);
1405       xid=(unsigned long)font;
1406 
1407       // Destroy pattern
1408       FcPatternDestroy(pattern);
1409 
1410       // Uh-oh, we failed
1411       if(!xid){ throw FXFontException("unable to create font"); }
1412 
1413 #else                                   // Using XLFD
1414 
1415       char fontname[MAX_XLFD];
1416 
1417       // X11 font specification
1418       if(hints&FONTHINT_X11){
1419 
1420         FXTRACE((150,"%s::create: X11 font=\"%s\"\n",getClassName(),wantedName.text()));
1421 
1422         // Try load the font
1423         font=XLoadQueryFont(DISPLAY(getApp()),wantedName.text());
1424         }
1425 
1426       // Platform independent specification
1427       else{
1428 
1429         FXTRACE((150,"%s::create: findbestfont\n",getClassName()));
1430 
1431         // Try load best font
1432         font=XLoadQueryFont(DISPLAY(getApp()),findbestfont(fontname));
1433         }
1434 
1435       // If we still don't have a font yet, try fallback fonts
1436       if(!font){
1437         FXTRACE((150,"%s::create: fallback\n",getClassName()));
1438         font=XLoadQueryFont(DISPLAY(getApp()),fallbackfont(DISPLAY(getApp()),hints));
1439         }
1440 
1441       // Remember font id
1442       if(font){ xid=((XFontStruct*)font)->fid; }
1443 
1444       // Uh-oh, we failed
1445       if(!xid){ throw FXFontException("unable to create font"); }
1446 
1447       // Dump some useful stuff
1448       FXTRACE((150,"min_char_or_byte2   = %d\n",((XFontStruct*)font)->min_char_or_byte2));
1449       FXTRACE((150,"max_char_or_byte2   = %d\n",((XFontStruct*)font)->max_char_or_byte2));
1450       FXTRACE((150,"default_char        = %c\n",((XFontStruct*)font)->default_char));
1451       FXTRACE((150,"min_bounds.lbearing = %d\n",((XFontStruct*)font)->min_bounds.lbearing));
1452       FXTRACE((150,"min_bounds.rbearing = %d\n",((XFontStruct*)font)->min_bounds.rbearing));
1453       FXTRACE((150,"min_bounds.width    = %d\n",((XFontStruct*)font)->min_bounds.width));
1454       FXTRACE((150,"min_bounds.ascent   = %d\n",((XFontStruct*)font)->min_bounds.ascent));
1455       FXTRACE((150,"min_bounds.descent  = %d\n",((XFontStruct*)font)->min_bounds.descent));
1456       FXTRACE((150,"max_bounds.lbearing = %d\n",((XFontStruct*)font)->max_bounds.lbearing));
1457       FXTRACE((150,"max_bounds.rbearing = %d\n",((XFontStruct*)font)->max_bounds.rbearing));
1458       FXTRACE((150,"max_bounds.width    = %d\n",((XFontStruct*)font)->max_bounds.width));
1459       FXTRACE((150,"max_bounds.ascent   = %d\n",((XFontStruct*)font)->max_bounds.ascent));
1460       FXTRACE((150,"max_bounds.descent  = %d\n",((XFontStruct*)font)->max_bounds.descent));
1461 #endif
1462 
1463 #else
1464       FXchar buffer[256];
1465 
1466       // Windows will not support the X11 font string specification method
1467       if(hints&FONTHINT_X11){ fxerror("%s::create: this method of font specification not supported under Windows.\n",getClassName()); }
1468 
1469       // Hang on to this for text metrics functions
1470       dc=CreateCompatibleDC(NULL);
1471 
1472       // Now fill in the fields
1473       LOGFONT lf;
1474       lf.lfHeight=-MulDiv(wantedSize,GetDeviceCaps((HDC)dc,LOGPIXELSY),720);
1475       lf.lfWidth=0;
1476       lf.lfEscapement=0;
1477       lf.lfOrientation=0;
1478       lf.lfWeight=wantedWeight;
1479       if((wantedSlant==FONTSLANT_ITALIC) || (wantedSlant==FONTSLANT_OBLIQUE))
1480         lf.lfItalic=TRUE;
1481       else
1482         lf.lfItalic=FALSE;
1483       lf.lfUnderline=FALSE;
1484       lf.lfStrikeOut=FALSE;
1485 
1486       // Character set encoding
1487       lf.lfCharSet=FXFontEncoding2CharSet(wantedEncoding);
1488 
1489       // Other hints
1490       lf.lfOutPrecision=OUT_DEFAULT_PRECIS;
1491       if(hints&FONTHINT_SYSTEM) lf.lfOutPrecision=OUT_RASTER_PRECIS;
1492       if(hints&FONTHINT_SCALABLE) lf.lfOutPrecision=OUT_TT_PRECIS;
1493       if(hints&FONTHINT_POLYMORPHIC) lf.lfOutPrecision=OUT_TT_PRECIS;
1494 
1495       // Clip precision
1496       lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;
1497 
1498       // Quality
1499       lf.lfQuality=DEFAULT_QUALITY;
1500 
1501       // Pitch and Family
1502       lf.lfPitchAndFamily=0;
1503 
1504       // Pitch
1505       if(hints&FONTPITCH_FIXED) lf.lfPitchAndFamily|=FIXED_PITCH;
1506       else if(hints&FONTPITCH_VARIABLE) lf.lfPitchAndFamily|=VARIABLE_PITCH;
1507       else lf.lfPitchAndFamily|=DEFAULT_PITCH;
1508 
1509       // Family
1510       if(hints&FONTHINT_DECORATIVE) lf.lfPitchAndFamily|=FF_DECORATIVE;
1511       else if(hints&FONTHINT_MODERN) lf.lfPitchAndFamily|=FF_MODERN;
1512       else if(hints&FONTHINT_ROMAN) lf.lfPitchAndFamily|=FF_ROMAN;
1513       else if(hints&FONTHINT_SCRIPT) lf.lfPitchAndFamily|=FF_SCRIPT;
1514       else if(hints&FONTHINT_SWISS) lf.lfPitchAndFamily|=FF_SWISS;
1515       else lf.lfPitchAndFamily|=FF_DONTCARE;
1516 
1517       // Font substitution
1518       if(!wantedName.empty()){
1519         strncpy(lf.lfFaceName,getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",wantedName.text(),wantedName.text()),sizeof(lf.lfFaceName));
1520         lf.lfFaceName[sizeof(lf.lfFaceName)-1]='\0';
1521         }
1522       else{
1523         lf.lfFaceName[0]='\0';
1524         }
1525 
1526       // Here we go!
1527       xid=CreateFontIndirect(&lf);
1528 
1529       // Uh-oh, we failed
1530       if(!xid){ throw FXFontException("unable to create font"); }
1531 
1532       // Obtain text metrics
1533       FXCALLOC(&font,TEXTMETRIC,1);
1534       SelectObject((HDC)dc,xid);
1535       GetTextMetrics((HDC)dc,(TEXTMETRIC*)font);
1536 
1537       // Get actual face name
1538       GetTextFace((HDC)dc,sizeof(buffer),buffer);
1539       actualName=buffer;
1540       actualSize=MulDiv(((TEXTMETRIC*)font)->tmHeight,720,GetDeviceCaps((HDC)dc,LOGPIXELSY)); // FIXME no sigar yet?
1541       actualWeight=((TEXTMETRIC*)font)->tmWeight;
1542       actualSlant=((TEXTMETRIC*)font)->tmItalic?FONTSLANT_ITALIC:FONTSLANT_REGULAR;
1543       actualSetwidth=0;
1544       actualEncoding=CharSet2FXFontEncoding(((TEXTMETRIC*)font)->tmCharSet);
1545 #endif
1546 
1547       // What was really matched
1548       FXTRACE((100,"wantedName=%s wantedSize=%d wantedWeight=%d wantedSlant=%d wantedSetwidth=%d wantedEncoding=%d\n",wantedName.text(),wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding));
1549       FXTRACE((100,"actualName=%s actualSize=%d actualWeight=%d actualSlant=%d actualSetwidth=%d actualEncoding=%d\n",actualName.text(),actualSize,actualWeight,actualSlant,actualSetwidth,actualEncoding));
1550       }
1551     }
1552   }
1553 
1554 
1555 // Detach font
detach()1556 void FXFont::detach(){
1557   if(xid){
1558     FXTRACE((100,"%s::detach %p\n",getClassName(),this));
1559 
1560 #ifndef WIN32
1561 
1562     // Free font struct w/o doing anything else...
1563 #ifdef HAVE_XFT_H
1564     XftFontClose(DISPLAY(getApp()),(XftFont*)font);
1565 #else
1566     XFreeFont(DISPLAY(getApp()),(XFontStruct*)font);
1567 #endif
1568 
1569 #else
1570 
1571     // Free font metrics
1572     FXFREE(&font);
1573 #endif
1574 
1575     // Forget all about actual font
1576     actualName=FXString::null;
1577     actualSize=0;
1578     actualWeight=0;
1579     actualSlant=0;
1580     actualSetwidth=0;
1581     actualEncoding=0;
1582     font=NULL;
1583     xid=0;
1584     }
1585   }
1586 
1587 
1588 // Destroy font
destroy()1589 void FXFont::destroy(){
1590   if(xid){
1591     if(getApp()->isInitialized()){
1592       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
1593 
1594 #ifndef WIN32
1595 
1596       // Free font
1597 #ifdef HAVE_XFT_H
1598       XftFontClose(DISPLAY(getApp()),(XftFont*)font);
1599 #else
1600       XFreeFont(DISPLAY(getApp()),(XFontStruct*)font);
1601 #endif
1602 
1603 #else
1604 
1605       // Necessary to prevent resource leak
1606       SelectObject((HDC)dc,GetStockObject(SYSTEM_FONT));
1607 
1608       // Delete font
1609       DeleteObject((HFONT)xid);
1610 
1611       // Delete dummy DC
1612       DeleteDC((HDC)dc);
1613 
1614       // Free font metrics
1615       FXFREE(&font);
1616 #endif
1617       }
1618 
1619     // Forget all about actual font
1620     actualName=FXString::null;
1621     actualSize=0;
1622     actualWeight=0;
1623     actualSlant=0;
1624     actualSetwidth=0;
1625     actualEncoding=0;
1626     font=NULL;
1627     xid=0;
1628     }
1629   }
1630 
1631 
1632 // Does font have given character glyph?
hasChar(FXint ch) const1633 FXbool FXFont::hasChar(FXint ch) const {
1634   if(font) return HASCHAR(font,ch);
1635   return FALSE;
1636   }
1637 
1638 
1639 // Get first character glyph in font
getMinChar() const1640 FXint FXFont::getMinChar() const {
1641   if(font) return FIRSTCHAR(font);
1642   return 0;
1643   }
1644 
1645 
1646 // Get last character glyph in font
getMaxChar() const1647 FXint FXFont::getMaxChar() const {
1648   if(font) return LASTCHAR(font);
1649   return 0;
1650   }
1651 
1652 
1653 // Get font leading [that is lead-ing as in Pb!]
getFontLeading() const1654 FXint FXFont::getFontLeading() const {
1655   if(font){
1656 #ifndef WIN32
1657 #ifdef HAVE_XFT_H
1658     return 0; // TODO
1659 #else
1660     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent-((XFontStruct*)font)->max_bounds.ascent-((XFontStruct*)font)->max_bounds.descent;
1661 #endif
1662 #else
1663     return ((TEXTMETRIC*)font)->tmExternalLeading;
1664 #endif
1665     }
1666   return 0;
1667   }
1668 
1669 
1670 // Get font line spacing [height+leading]
getFontSpacing() const1671 FXint FXFont::getFontSpacing() const {
1672   if(font){
1673 #ifndef WIN32
1674 #ifdef HAVE_XFT_H
1675     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1676 #else
1677     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent;
1678 #endif
1679 #else
1680     return ((TEXTMETRIC*)font)->tmHeight; // tmHeight includes font point size plus internal leading
1681 #endif
1682     }
1683   return 1;
1684   }
1685 
1686 
1687 // Left bearing
leftBearing(FXchar ch) const1688 FXint FXFont::leftBearing(FXchar ch) const {
1689   if(font){
1690 #ifndef WIN32
1691 #ifdef HAVE_XFT_H
1692     return 0; // FIXME
1693 #else
1694     if(((XFontStruct*)font)->per_char){
1695       if(!HASCHAR(font,ch)){ ch=((XFontStruct*)font)->default_char; }
1696       return ((XFontStruct*)font)->per_char[(FXuint)ch-((XFontStruct*)font)->min_char_or_byte2].lbearing;
1697       }
1698     return ((XFontStruct*)font)->max_bounds.lbearing;
1699 #endif
1700 #else
1701     return 0; // FIXME
1702 #endif
1703     }
1704   return 0;
1705   }
1706 
1707 
1708 // Right bearing
rightBearing(FXchar ch) const1709 FXint FXFont::rightBearing(FXchar ch) const {
1710   if(font){
1711 #ifndef WIN32
1712 #ifdef HAVE_XFT_H
1713     return 0; // FIXME
1714 #else
1715     if(((XFontStruct*)font)->per_char){
1716       if(!HASCHAR(font,ch)){ ch=((XFontStruct*)font)->default_char; }
1717       return ((XFontStruct*)font)->per_char[(FXuint)ch-((XFontStruct*)font)->min_char_or_byte2].rbearing;
1718       }
1719     return ((XFontStruct*)font)->max_bounds.rbearing;
1720 #endif
1721 #else
1722     return 0; // FIXME
1723 #endif
1724     }
1725   return 0;
1726   }
1727 
1728 
1729 // Is it a mono space font
isFontMono() const1730 FXbool FXFont::isFontMono() const {
1731   if(font){
1732 #ifndef WIN32
1733 #ifdef HAVE_XFT_H
1734     XGlyphInfo i_extents,m_extents;
1735     XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)"i",1,&i_extents); // FIXME better than before but no cigar yet
1736     XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)"M",1,&m_extents);
1737     return i_extents.xOff==m_extents.xOff;
1738 #else
1739     return ((XFontStruct*)font)->min_bounds.width == ((XFontStruct*)font)->max_bounds.width;
1740 #endif
1741 #else
1742     return !(((TEXTMETRIC*)font)->tmPitchAndFamily&TMPF_FIXED_PITCH);
1743 #endif
1744     }
1745   return TRUE;
1746   }
1747 
1748 
1749 // Get font width
getFontWidth() const1750 FXint FXFont::getFontWidth() const {
1751   if(font){
1752 #ifndef WIN32
1753 #ifdef HAVE_XFT_H
1754     return ((XftFont*)font)->max_advance_width;
1755 #else
1756     return ((XFontStruct*)font)->max_bounds.width;
1757 #endif
1758 #else
1759     return ((TEXTMETRIC*)font)->tmMaxCharWidth;
1760 #endif
1761     }
1762   return 1;
1763   }
1764 
1765 
1766 // Get font height
getFontHeight() const1767 FXint FXFont::getFontHeight() const {
1768   if(font){
1769 #ifndef WIN32
1770 #ifdef HAVE_XFT_H
1771     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1772 #else
1773     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent;  // This is wrong!
1774     //return ((XFontStruct*)font)->max_bounds.ascent+((XFontStruct*)font)->max_bounds.descent;  // This is right!
1775 #endif
1776 #else
1777     return ((TEXTMETRIC*)font)->tmHeight;
1778 #endif
1779     }
1780   return 1;
1781   }
1782 
1783 
1784 // Get font ascent
getFontAscent() const1785 FXint FXFont::getFontAscent() const {
1786   if(font){
1787 #ifndef WIN32
1788 #ifdef HAVE_XFT_H
1789     return ((XftFont*)font)->ascent;
1790 #else
1791     return ((XFontStruct*)font)->ascent;
1792 #endif
1793 #else
1794     return ((TEXTMETRIC*)font)->tmAscent;
1795 #endif
1796     }
1797   return 1;
1798   }
1799 
1800 
1801 // Get font descent
getFontDescent() const1802 FXint FXFont::getFontDescent() const {
1803   if(font){
1804 #ifndef WIN32
1805 #ifdef HAVE_XFT_H
1806     return ((XftFont*)font)->descent;
1807 #else
1808     return ((XFontStruct*)font)->descent;
1809 #endif
1810 #else
1811     return ((TEXTMETRIC*)font)->tmDescent;
1812 #endif
1813     }
1814   return 0;
1815   }
1816 
1817 
1818 // Text width
getTextWidth(const FXchar * text,FXuint n) const1819 FXint FXFont::getTextWidth(const FXchar *text,FXuint n) const {
1820   if(!text && n){ fxerror("%s::getTextWidth: NULL string argument\n",getClassName()); }
1821   if(font){
1822 #ifndef WIN32
1823 #ifdef HAVE_XFT_H
1824     XGlyphInfo extents;
1825     XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)text,n,&extents);
1826     return extents.xOff;
1827 #else
1828     return XTextWidth((XFontStruct*)font,text,n);
1829 #endif
1830 #else
1831     SIZE size;
1832     FXASSERT(dc!=NULL);
1833     GetTextExtentPoint32((HDC)dc,text,n,&size);
1834     return size.cx;
1835 #endif
1836     }
1837   return n;
1838   }
1839 
1840 
1841 // Text width
getTextWidth(const FXString & text) const1842 FXint FXFont::getTextWidth(const FXString& text) const {
1843   return getTextWidth(text.text(),text.length());
1844   }
1845 
1846 
1847 // Text height
getTextHeight(const FXchar * text,FXuint n) const1848 FXint FXFont::getTextHeight(const FXchar *text,FXuint n) const {
1849   if(!text && n){ fxerror("%s::getTextHeight: NULL string argument\n",getClassName()); }
1850   if(font){
1851 #ifndef WIN32
1852 #ifdef HAVE_XFT_H
1853 //    XGlyphInfo extents;
1854 //    XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)text,n,&extents);
1855 //    return extents.height; // TODO: Is this correct?
1856 
1857     // Patch from ivan.markov@wizcom.bg
1858     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1859 #else
1860     XCharStruct chst; int dir,asc,desc;
1861     XTextExtents((XFontStruct*)font,text,n,&dir,&asc,&desc,&chst);
1862     return asc+desc;
1863 #endif
1864 #else
1865     SIZE size;
1866     FXASSERT(dc!=NULL);
1867     GetTextExtentPoint32((HDC)dc,text,n,&size);
1868     return size.cy;
1869 #endif
1870     }
1871   return 1;
1872   }
1873 
1874 
1875 // Text height
getTextHeight(const FXString & text) const1876 FXint FXFont::getTextHeight(const FXString& text) const {
1877   return getTextHeight(text.text(),text.length());
1878   }
1879 
1880 
1881 /*******************************************************************************/
1882 
1883 
1884 // Function to sort by name, weight, slant, and size
comparefont(const void * a,const void * b)1885 static int comparefont(const void *a,const void *b){
1886   register FXFontDesc *fa=(FXFontDesc*)a;
1887   register FXFontDesc *fb=(FXFontDesc*)b;
1888   register FXint cmp=strcmp(fa->face,fb->face);
1889   return cmp ? cmp : (fa->weight!=fb->weight) ? fa->weight-fb->weight : (fa->slant!=fb->slant) ? fa->slant-fb->slant : fa->size-fb->size;
1890   }
1891 
1892 
1893 #ifndef WIN32
1894 
1895 #ifdef HAVE_XFT_H
1896 
1897 /*
1898 // TODO
1899 const FXchar* FXFont::encodingName(FXFontEncoding encoding) {
1900   switch(encoding){
1901     case FONTENCODING_ISO_8859_1:  return "ISO-8859-1";
1902     case FONTENCODING_ISO_8859_2:  return "ISO-8859-2";
1903     case FONTENCODING_ISO_8859_3:  return "ISO-8859-3";
1904     case FONTENCODING_ISO_8859_4:  return "ISO-8859-4";
1905     case FONTENCODING_ISO_8859_5:  return "ISO-8859-5";
1906     //case FONTENCODING_ISO_8859_6:  return "ISO-8859-6";
1907     case FONTENCODING_ISO_8859_7:  return "ISO-8859-7";
1908     //case FONTENCODING_ISO_8859_8:  return "ISO-8859-8";
1909     case FONTENCODING_ISO_8859_9:  return "ISO-8859-9";
1910     //case FONTENCODING_ISO_8859_10: return "ISO-8859-10";
1911     //case FONTENCODING_ISO_8859_11: return "ISO-8859-11";
1912     //case FONTENCODING_ISO_8859_13: return "ISO-8859-12";
1913     //case FONTENCODING_ISO_8859_14: return "ISO-8859-13";
1914     case FONTENCODING_ISO_8859_15: return "ISO-8859-14";
1915     //case FONTENCODING_ISO_8859_16: return "ISO-8859-15";
1916     case FONTENCODING_KOI8:        return "ISO-8859-1"; // TODO
1917     case FONTENCODING_KOI8_R:      return "ISO-8859-1"; // TODO
1918     case FONTENCODING_KOI8_U:      return "ISO-8859-1"; // TODO
1919     case FONTENCODING_KOI8_UNIFIED:return "ISO-8859-1"; // TODO
1920     }
1921   return "ISO-8859-1";
1922   }
1923 */
1924 
1925 /*
1926 void FXFont::encoding2FcCharSet(void *cs,FXFontEncoding encoding){
1927   FXTextCodec* textcodec = FXTextCodec::codecForName(encodingName(encoding));
1928   FXASSERT(textcodec != NULL);
1929 
1930   FcCharSet *charSet = (FcCharSet*)cs;
1931 
1932   FXuchar charset1[256];
1933   FXwchar charset4[256];
1934   // TODO: There should be a way in FXTextCodec to return the single-byte ranges covered by the particular charset
1935   for(int i = 0; i < 256; i++)
1936     charset1[i] = i >= 32 && (i < 0x80 || i > 0x9f) && i < 128? (unsigned char)i: 32;
1937 
1938   const FXuchar* chs1 = charset1;
1939   FXwchar* chs4 = charset4;
1940   textcodec->toUnicode(chs4, 256LU, chs1, 256LU);
1941 
1942   //for(int j = 0; j < 256; j++)
1943 //    FcCharSetAddChar(charSet, 33  / * charset4[j] * /);
1944   }
1945 */
1946 
1947 
1948 
1949 // List all fonts that match the passed requirements
listFonts(FXFontDesc * & fonts,FXuint & numfonts,const FXString & face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h)1950 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
1951 #if FC_VERSION >= FCWIDTHVERSION
1952   FcObjectSet *objset = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_SCALABLE, FC_WIDTH, FC_PIXEL_SIZE, FC_WEIGHT, FC_SLANT, NULL);
1953 #else
1954   FcObjectSet *objset = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, FC_SLANT, NULL);
1955 #endif
1956 
1957   // The pattern will contain all passed required font properties
1958   FcPattern *pattern=buildPatternXft(face.text(),0,wt,sl,sw,en,h);
1959 
1960   FcFontSet *fontset=FcFontList(0,pattern,objset);
1961 
1962   numfonts = fontset->nfont;
1963   if(numfonts>0){
1964     FXMALLOC(&fonts,FXFontDesc,numfonts);
1965 
1966     unsigned realnumfonts=0;
1967 
1968     for(unsigned i=0; i<numfonts; i++){
1969       FXFontDesc *desc = &fonts[realnumfonts];
1970       FcPattern *p = fontset->fonts[i];
1971 
1972       FcChar8 *family, *foundry;
1973       int spacing, setwidth, weight, slant, size;
1974       FcBool scalable;
1975 
1976       if(FcPatternGetString(p, FC_FAMILY, 0, &family) != FcResultMatch)
1977         continue;
1978 
1979       FXString fc = (const char*)family;
1980 
1981       if(FcPatternGetString(p, FC_FOUNDRY, 0, &foundry) == FcResultMatch)
1982         fc = fc + " [" + (const char*)foundry + "]";
1983 
1984       strncpy(desc->face, fc.text(), sizeof(desc->face) - 1);
1985 
1986 #if FC_VERSION >= FCWIDTHVERSION
1987       if(FcPatternGetInteger(p, FC_WIDTH, 0, &setwidth) == FcResultMatch)
1988         desc->setwidth = fcSetWidth2SetWidth(setwidth);
1989       else
1990         desc->setwidth = FONTSETWIDTH_NORMAL;
1991 #else
1992         desc->setwidth = FONTSETWIDTH_NORMAL;
1993 #endif
1994 
1995       if(FcPatternGetInteger(p, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1996         desc->size = (int)(size*10/getDPIDiffXft() + 0.5);
1997       else
1998         desc->size = 0;
1999 
2000       if(FcPatternGetInteger(p, FC_WEIGHT, 0, &weight) == FcResultMatch)
2001         desc->weight = fcWeight2Weight(weight);
2002       else
2003         desc->weight = FONTWEIGHT_NORMAL;
2004 
2005       if(FcPatternGetInteger(p, FC_SLANT, 0, &slant) == FcResultMatch)
2006         desc->slant = fcSlant2Slant(slant);
2007       else
2008         desc->slant = FONTSLANT_REGULAR;
2009 
2010       if(FcPatternGetInteger(p, FC_SPACING, 0, &spacing) == FcResultMatch){
2011         if(spacing==FC_PROPORTIONAL)
2012           desc->flags|=FONTPITCH_VARIABLE;
2013         else if(spacing==FC_MONO)
2014           desc->flags|=FONTPITCH_FIXED;
2015         }
2016       else{
2017         desc->flags|=FONTPITCH_VARIABLE;
2018         }
2019 
2020       if(FcPatternGetBool(p, FC_SCALABLE, 0, &scalable) == FcResultMatch){
2021         if(scalable)
2022           desc->flags|=FONTHINT_SCALABLE;
2023         }
2024 
2025       desc->encoding=en; //FIXME fcEncoding2Encoding(encoding);
2026 
2027       if(face.empty()){
2028         // Should return one font entry for each font family
2029         FXbool addIt=TRUE;
2030         for(unsigned j=0; j<realnumfonts; j++)
2031           if(strcmp(fonts[j].face, desc->face) == 0){
2032             addIt = FALSE;
2033             break;
2034           }
2035 
2036         if(!addIt)
2037           continue;
2038         }
2039 
2040       realnumfonts++;
2041 
2042       // Dump what we have found out
2043       FXTRACE((150, "Font=%s weight=%d slant=%d size=%3d setwidth=%d encoding=%d flags=%d\n", desc->face, desc->weight, desc->slant, desc->size, desc->setwidth, desc->encoding, desc->flags));
2044       }
2045 
2046     if(realnumfonts<numfonts){
2047       numfonts = realnumfonts;
2048 
2049       if(numfonts>0)
2050         FXRESIZE(&fonts, FXFontDesc, numfonts);
2051       else
2052         FXFREE(&fonts);
2053       }
2054 
2055     // Sort them by name, weight, slant, and size respectively
2056     if(numfonts>0){
2057       qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2058       }
2059     }
2060 
2061   FcFontSetDestroy(fontset);
2062   FcObjectSetDestroy(objset);
2063   FcPatternDestroy(pattern);
2064 
2065   return numfonts > 0;
2066   }
2067 
2068 #else                                   // Using XLFD
2069 
2070 
2071 // List all fonts matching hints
listFonts(FXFontDesc * & fonts,FXuint & numfonts,const FXString & face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h)2072 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
2073   FXchar candidate[MAX_XLFD],family[104],foundry[104],fullname[104],*field[14],**fnames;
2074   FXuint size,weight,slant,encoding,setwidth,flags;
2075   const FXchar *scalable,*facename,*foundryname;
2076   FXint screenres,xres,yres;
2077   FXint numfnames,f,j;
2078 
2079   fonts=NULL;
2080   numfonts=0;
2081 
2082   // Gotta have display open!
2083   if(!FXApp::instance()){ fxerror("FXFont::listFonts: no application object.\n"); }
2084   if(!DISPLAY(FXApp::instance())){ fxerror("FXFont::listFonts: trying to list fonts before opening display.\n"); }
2085 
2086   // Screen resolution may be overidden by registry
2087   screenres=FXApp::app->reg().readUnsignedEntry("SETTINGS","screenres",100);
2088 
2089   // Validate
2090   if(screenres<50) screenres=50;
2091   if(screenres>200) screenres=200;
2092 
2093   FXTRACE((150,"Listing fonts for screenres=%d:\n",screenres));
2094 
2095   // Family and foundry name
2096   familyandfoundryfromname(family,foundry,face.text());
2097 
2098   FXTRACE((150,"family=\"%s\", foundry=\"%s\"\n",family,foundry));
2099 
2100   // Define pattern to match against
2101   if(h&FONTHINT_X11){
2102     facename="*";
2103     if(family[0]) facename=family;
2104     strncpy(candidate,facename,MAX_XLFD);
2105     }
2106 
2107   // Match XLFD fonts; try to limit the number by using
2108   // some of the info we already have acquired.
2109   else{
2110     scalable="*";
2111     if(h&FONTHINT_SCALABLE) scalable="0";
2112     facename="*";
2113     if(family[0]) facename=family;
2114     foundryname="*";
2115     if(foundry[0]) foundryname=foundry;
2116     sprintf(candidate,"-%s-%s-*-*-*-*-%s-%s-*-*-*-%s-*-*",foundryname,facename,scalable,scalable,scalable);
2117     }
2118 
2119   // Get list of all font names
2120   fnames=listfontnames(DISPLAY(FXApp::instance()),candidate,numfnames);
2121   if(!fnames) return FALSE;
2122 
2123   // Make room to receive face names
2124   FXMALLOC(&fonts,FXFontDesc,numfnames);
2125   if(!fonts){ XFreeFontNames(fnames); return FALSE; }
2126 
2127   // Add all matching fonts to the list
2128   for(f=0; f<numfnames; f++){
2129     strncpy(candidate,fnames[f],MAX_XLFD);
2130 
2131     // XLFD font name; parse out unique face names
2132     if(parsefontname(field,candidate)){
2133 
2134       flags=0;
2135 
2136       // Get encoding
2137       encoding=encodingfromxlfd(field[XLFD_REGISTRY],field[XLFD_ENCODING]);
2138 
2139       // Skip if no match
2140       if((en!=FONTENCODING_DEFAULT) && (en!=encoding)) continue;
2141 
2142       // Get pitch
2143       flags|=pitchfromtext(field[XLFD_SPACING]);
2144 
2145       // Skip this font if pitch does not match
2146       if((h&FONTPITCH_FIXED) && !(flags&FONTPITCH_FIXED)) continue;
2147       if((h&FONTPITCH_VARIABLE) && !(flags&FONTPITCH_VARIABLE)) continue;
2148 
2149       // Skip if weight does not match
2150       weight=weightfromtext(field[XLFD_WEIGHT]);
2151       if((wt!=FONTWEIGHT_DONTCARE) && (wt!=weight)) continue;
2152 
2153       // Skip if slant does not match
2154       slant=slantfromtext(field[XLFD_SLANT]);
2155       if((sl!=FONTSLANT_DONTCARE) && (sl!=slant)) continue;
2156 
2157       // Skip if setwidth does not match
2158       setwidth=setwidthfromtext(field[XLFD_SETWIDTH]);
2159       if((sw!=FONTSETWIDTH_DONTCARE) && (sw!=setwidth)) continue;
2160 
2161       // Scalable
2162       if(EQUAL1(field[XLFD_PIXELSIZE],'0') && EQUAL1(field[XLFD_POINTSIZE],'0') && EQUAL1(field[XLFD_AVERAGE],'0')){
2163         flags|=FONTHINT_SCALABLE;
2164         }
2165 
2166       // Polymorphic
2167       if(EQUAL1(field[XLFD_WEIGHT],'0') || EQUAL1(field[XLFD_SETWIDTH],'0') || EQUAL1(field[XLFD_SLANT],'0') || EQUAL1(field[XLFD_ADDSTYLE],'0')){
2168         flags|=FONTHINT_POLYMORPHIC;
2169         }
2170 
2171       // Get Font resolution
2172       if(EQUAL1(field[XLFD_RESOLUTION_X],'0') && EQUAL1(field[XLFD_RESOLUTION_Y],'0')){
2173         xres=screenres;
2174         yres=screenres;
2175         }
2176       else{
2177         xres=atoi(field[XLFD_RESOLUTION_X]);
2178         yres=atoi(field[XLFD_RESOLUTION_Y]);
2179         }
2180 
2181       // Get size, corrected for screen resolution
2182       if(!(flags&FONTHINT_SCALABLE)){
2183         size=(yres*atoi(field[XLFD_POINTSIZE]))/screenres;
2184         }
2185       else{
2186         size=0;
2187         }
2188 
2189       // Dump what we have found out
2190       FXTRACE((160,"Font=\"%s\" weight=%d slant=%d size=%3d setwidth=%d encoding=%d\n",field[XLFD_FAMILY],weight,slant,size,setwidth,encoding));
2191 
2192       // If NULL face name, just list one of each face
2193       sprintf(fullname,"%s [%s]",field[XLFD_FAMILY],field[XLFD_FOUNDRY]);
2194       if(family[0]=='\0'){
2195         for(j=numfonts-1; j>=0; j--){
2196           if(strcmp(fullname,fonts[j].face)==0) goto next;
2197           }
2198         }
2199 
2200       // Add this font
2201       strncpy(fonts[numfonts].face,fullname,sizeof(fonts[0].face));
2202       fonts[numfonts].size=size;
2203       fonts[numfonts].weight=weight;
2204       fonts[numfonts].slant=slant;
2205       fonts[numfonts].encoding=encoding;
2206       fonts[numfonts].setwidth=setwidth;
2207       fonts[numfonts].flags=flags;
2208       numfonts++;
2209 
2210       // Next font
2211 next: continue;
2212       }
2213 
2214     // X11 font, add it to the list
2215     strncpy(fonts[numfonts].face,fnames[f],sizeof(fonts[0].face));
2216     fonts[numfonts].size=0;
2217     fonts[numfonts].weight=FONTWEIGHT_DONTCARE;
2218     fonts[numfonts].slant=FONTSLANT_DONTCARE;
2219     fonts[numfonts].encoding=FONTENCODING_DEFAULT;
2220     fonts[numfonts].setwidth=FONTSETWIDTH_DONTCARE;
2221     fonts[numfonts].flags=FONTHINT_X11;
2222     numfonts++;
2223     }
2224 
2225   // Any fonts found?
2226   if(numfonts==0){
2227     FXFREE(&fonts);
2228     XFreeFontNames(fnames);
2229     return FALSE;
2230     }
2231 
2232   // Realloc to shrink the block
2233   FXRESIZE(&fonts,FXFontDesc,numfonts);
2234 
2235   // Sort them by name, weight, slant, and size respectively
2236   qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2237 
2238 //   FXTRACE((150,"%d fonts:\n",numfonts));
2239 //   for(f=0; f<numfonts; f++){
2240 //     FXTRACE((150,"Font=\"%s\" weight=%d slant=%d size=%3d setwidth=%d encoding=%d\n",fonts[f].face,fonts[f].weight,fonts[f].slant,fonts[f].size,fonts[f].setwidth,fonts[f].encoding));
2241 //     }
2242 //   FXTRACE((150,"\n\n"));
2243 
2244   // Free the font names
2245   XFreeFontNames(fnames);
2246   return TRUE;
2247   }
2248 
2249 #endif
2250 
2251 
2252 #else
2253 
2254 
2255 // List all fonts matching hints
listFonts(FXFontDesc * & fonts,FXuint & numfonts,const FXString & face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h)2256 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
2257   register FXuint i,j;
2258 
2259   // Initialize return values
2260   fonts=NULL;
2261   numfonts=0;
2262 
2263   // This data gets passed into the callback function
2264   FXFontStore fontStore;
2265   HDC hdc=GetDC(GetDesktopWindow());
2266   SaveDC(hdc);
2267   fontStore.hdc=hdc;
2268   fontStore.fonts=fonts;
2269   fontStore.numfonts=numfonts;
2270   fontStore.desc.weight=wt;
2271   fontStore.desc.slant=sl;
2272   fontStore.desc.setwidth=sw;
2273   fontStore.desc.encoding=en;
2274   fontStore.desc.flags=h;
2275 
2276   // Fill in the appropriate fields of the LOGFONT structure. Note that
2277   // EnumFontFamiliesEx() only examines the lfCharSet, lfFaceName and
2278   // lpPitchAndFamily fields of this struct.
2279   LOGFONT lf;
2280   lf.lfHeight=0;
2281   lf.lfWidth=0;
2282   lf.lfEscapement=0;
2283   lf.lfOrientation=0;
2284   lf.lfWeight=0;
2285   lf.lfItalic=0;
2286   lf.lfUnderline=0;
2287   lf.lfStrikeOut=0;
2288   lf.lfCharSet=FXFontEncoding2CharSet(en);
2289   lf.lfOutPrecision=0;
2290   lf.lfClipPrecision=0;
2291   lf.lfQuality=0;
2292   lf.lfPitchAndFamily=0;                          // Should be MONO_FONT for Hebrew and Arabic?
2293   FXASSERT(face.length()<LF_FACESIZE);
2294   strncpy(lf.lfFaceName,face.text(),LF_FACESIZE);
2295 
2296   // Start enumerating!
2297   EnumFontFamiliesEx(hdc,&lf,EnumFontFamExProc,(LPARAM)&fontStore,0);
2298   RestoreDC(hdc,-1);
2299   ReleaseDC(GetDesktopWindow(),hdc);
2300 
2301   // Copy stuff back from the store
2302   fonts=fontStore.fonts;
2303   numfonts=fontStore.numfonts;
2304 
2305   // Any fonts found?
2306   if(numfonts==0){
2307     FXFREE(&fonts);
2308     return FALSE;
2309     }
2310 
2311   // Sort them by name, weight, slant, and size respectively
2312   qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2313 
2314   // Weed out duplicates if we were just listing the face names
2315   if(lf.lfCharSet==DEFAULT_CHARSET && lf.lfFaceName[0]==0){
2316     i=j=1;
2317     while(j<numfonts){
2318       if(strcmp(fonts[i-1].face,fonts[j].face)!=0){
2319         fonts[i]=fonts[j];
2320         i++;
2321         }
2322       j++;
2323       }
2324     numfonts=i;
2325     }
2326 
2327   // Realloc to shrink the block
2328   FXRESIZE(&fonts,FXFontDesc,numfonts);
2329 
2330 //   FXTRACE((150,"%d fonts:\n",numfonts));
2331 //   for(FXuint f=0; f<numfonts; f++){
2332 //     FXTRACE((150,"Font=%s weight=%d slant=%d size=%3d setwidth=%d encoding=%d\n",fonts[f].face,fonts[f].weight,fonts[f].slant,fonts[f].size,fonts[f].setwidth,fonts[f].encoding));
2333 //     }
2334 //   FXTRACE((150,"\n\n"));
2335 
2336   return TRUE;
2337   }
2338 
2339 #endif
2340 
2341 
2342 /*******************************************************************************/
2343 
2344 
2345 // Font style table
2346 static const ENTRY styletable[]={
2347   {"",FONTHINT_DONTCARE},
2348   {"decorative",FONTHINT_DECORATIVE},
2349   {"modern",FONTHINT_MODERN},
2350   {"roman",FONTHINT_ROMAN},
2351   {"script",FONTHINT_SCRIPT},
2352   {"swiss",FONTHINT_SWISS},
2353   {"system",FONTHINT_SYSTEM}
2354   };
2355 
2356 
2357 // Font pitch table
2358 static const ENTRY pitchtable[]={
2359   {"",FONTPITCH_DEFAULT},
2360   {"mono",FONTPITCH_FIXED},
2361   {"fixed",FONTPITCH_FIXED},
2362   {"constant",FONTPITCH_FIXED},
2363   {"variable",FONTPITCH_VARIABLE},
2364   {"proportional",FONTPITCH_VARIABLE},
2365   {"c",FONTPITCH_FIXED},
2366   {"m",FONTPITCH_FIXED},
2367   {"p",FONTPITCH_VARIABLE}
2368   };
2369 
2370 
2371 // Font text angles
2372 static const ENTRY slanttable[]={
2373   {"",FONTSLANT_DONTCARE},
2374   {"regular",FONTSLANT_REGULAR},
2375   {"italic",FONTSLANT_ITALIC},
2376   {"oblique",FONTSLANT_OBLIQUE},
2377   {"normal",FONTSLANT_REGULAR},
2378   {"reverse italic",FONTSLANT_REVERSE_ITALIC},
2379   {"reverse oblique",FONTSLANT_REVERSE_OBLIQUE},
2380   {"r",FONTSLANT_REGULAR},
2381   {"n",FONTSLANT_REGULAR},
2382   {"i",FONTSLANT_ITALIC},
2383   {"o",FONTSLANT_OBLIQUE},
2384   {"ri",FONTSLANT_REVERSE_ITALIC},
2385   {"ro",FONTSLANT_REVERSE_OBLIQUE}
2386   };
2387 
2388 
2389 // Character set encodings
2390 static const ENTRY encodingtable[]={
2391   {"",FONTENCODING_DEFAULT},
2392   {"iso8859-1",FONTENCODING_ISO_8859_1},
2393   {"iso8859-2",FONTENCODING_ISO_8859_2},
2394   {"iso8859-3",FONTENCODING_ISO_8859_3},
2395   {"iso8859-4",FONTENCODING_ISO_8859_4},
2396   {"iso8859-5",FONTENCODING_ISO_8859_5},
2397   {"iso8859-6",FONTENCODING_ISO_8859_6},
2398   {"iso8859-7",FONTENCODING_ISO_8859_7},
2399   {"iso8859-8",FONTENCODING_ISO_8859_8},
2400   {"iso8859-9",FONTENCODING_ISO_8859_9},
2401   {"iso8859-10",FONTENCODING_ISO_8859_10},
2402   {"iso8859-11",FONTENCODING_ISO_8859_11},
2403   {"iso8859-13",FONTENCODING_ISO_8859_13},
2404   {"iso8859-14",FONTENCODING_ISO_8859_14},
2405   {"iso8859-15",FONTENCODING_ISO_8859_15},
2406   {"iso8859-16",FONTENCODING_ISO_8859_16},
2407   {"koi8",FONTENCODING_KOI8},
2408   {"koi8-r",FONTENCODING_KOI8_R},
2409   {"koi8-u",FONTENCODING_KOI8_U},
2410   {"koi8-unified",FONTENCODING_KOI8_UNIFIED},
2411   {"cp437",FONTENCODING_CP437},
2412   {"cp850",FONTENCODING_CP850},
2413   {"cp851",FONTENCODING_CP851},
2414   {"cp852",FONTENCODING_CP852},
2415   {"cp855",FONTENCODING_CP855},
2416   {"cp856",FONTENCODING_CP856},
2417   {"cp857",FONTENCODING_CP857},
2418   {"cp860",FONTENCODING_CP860},
2419   {"cp861",FONTENCODING_CP861},
2420   {"cp862",FONTENCODING_CP862},
2421   {"cp863",FONTENCODING_CP863},
2422   {"cp864",FONTENCODING_CP864},
2423   {"cp865",FONTENCODING_CP865},
2424   {"cp866",FONTENCODING_CP866},
2425   {"cp869",FONTENCODING_CP869},
2426   {"cp870",FONTENCODING_CP870},
2427   {"cp1250",FONTENCODING_CP1250},
2428   {"cp1251",FONTENCODING_CP1251},
2429   {"cp1252",FONTENCODING_CP1252},
2430   {"cp1253",FONTENCODING_CP1253},
2431   {"cp1254",FONTENCODING_CP1254},
2432   {"cp1255",FONTENCODING_CP1255},
2433   {"cp1256",FONTENCODING_CP1256},
2434   {"cp1257",FONTENCODING_CP1257},
2435   {"cp1258",FONTENCODING_CP1258},
2436   {"cp874",FONTENCODING_CP874},
2437   {"ascii",FONTENCODING_ISO_8859_1}
2438   };
2439 
2440 
2441 // Set width table
2442 static const ENTRY setwidthtable[]={
2443   {"",FONTSETWIDTH_DONTCARE},
2444   {"ultracondensed",FONTSETWIDTH_ULTRACONDENSED},
2445   {"extracondensed",FONTSETWIDTH_EXTRACONDENSED},
2446   {"condensed",FONTSETWIDTH_CONDENSED},
2447   {"narrow",FONTSETWIDTH_NARROW},
2448   {"compressed",FONTSETWIDTH_COMPRESSED},
2449   {"semicondensed",FONTSETWIDTH_SEMICONDENSED},
2450   {"medium",FONTSETWIDTH_MEDIUM},
2451   {"normal",FONTSETWIDTH_NORMAL},
2452   {"regular",FONTSETWIDTH_REGULAR},
2453   {"semiexpanded",FONTSETWIDTH_SEMIEXPANDED},
2454   {"expanded",FONTSETWIDTH_EXPANDED},
2455   {"wide",FONTSETWIDTH_WIDE},
2456   {"extraexpanded",FONTSETWIDTH_EXTRAEXPANDED},
2457   {"ultraexpanded",FONTSETWIDTH_ULTRAEXPANDED},
2458   {"n",FONTSETWIDTH_NARROW},
2459   {"r",FONTSETWIDTH_REGULAR},
2460   {"c",FONTSETWIDTH_CONDENSED},
2461   {"w",FONTSETWIDTH_WIDE},
2462   {"m",FONTSETWIDTH_MEDIUM},
2463   {"x",FONTSETWIDTH_EXPANDED}
2464   };
2465 
2466 
2467 // Weight table
2468 static const ENTRY weighttable[]={
2469   {"",FONTWEIGHT_DONTCARE},
2470   {"thin",FONTWEIGHT_THIN},
2471   {"extralight",FONTWEIGHT_EXTRALIGHT},
2472   {"light",FONTWEIGHT_LIGHT},
2473   {"normal",FONTWEIGHT_NORMAL},
2474   {"regular",FONTWEIGHT_REGULAR},
2475   {"medium",FONTWEIGHT_MEDIUM},
2476   {"demibold",FONTWEIGHT_DEMIBOLD},
2477   {"bold",FONTWEIGHT_BOLD},
2478   {"extrabold",FONTWEIGHT_EXTRABOLD},
2479   {"heavy",FONTWEIGHT_HEAVY},
2480   {"black",FONTWEIGHT_BLACK},
2481   {"b",FONTWEIGHT_BOLD},
2482   {"l",FONTWEIGHT_LIGHT},
2483   {"n",FONTWEIGHT_NORMAL},
2484   {"r",FONTWEIGHT_REGULAR},
2485   {"m",FONTWEIGHT_MEDIUM},
2486   };
2487 
2488 
2489 // Search for value and return name
findbyvalue(const ENTRY * table,FXint n,FXuint value)2490 static FXString findbyvalue(const ENTRY* table,FXint n,FXuint value){
2491   for(int i=0; i<n; i++){ if(table[i].value==value) return table[i].name; }
2492   return FXStringVal(value);
2493   }
2494 
2495 
2496 // Search for name and return value
findbyname(const ENTRY * table,FXint n,const FXString & name)2497 static FXuint findbyname(const ENTRY* table,FXint n,const FXString& name){
2498   for(int i=0; i<n; i++){ if(comparecase(table[i].name,name)==0) return table[i].value; }
2499   return FXUIntVal(name);
2500   }
2501 
2502 
2503 // Get font description
getFontDesc(FXFontDesc & fontdesc) const2504 void FXFont::getFontDesc(FXFontDesc& fontdesc) const {
2505   strncpy(fontdesc.face,wantedName.text(),sizeof(fontdesc.face));
2506   fontdesc.size=wantedSize;
2507   fontdesc.weight=wantedWeight;
2508   fontdesc.slant=wantedSlant;
2509   fontdesc.setwidth=wantedSetwidth;
2510   fontdesc.encoding=wantedEncoding;
2511   fontdesc.flags=hints;
2512   }
2513 
2514 
2515 // Change font description
setFontDesc(const FXFontDesc & fontdesc)2516 void FXFont::setFontDesc(const FXFontDesc& fontdesc){
2517   wantedName=fontdesc.face;
2518   wantedSize=fontdesc.size;
2519   wantedWeight=fontdesc.weight;
2520   wantedSlant=fontdesc.slant;
2521   wantedSetwidth=fontdesc.setwidth;
2522   wantedEncoding=fontdesc.encoding;
2523   hints=fontdesc.flags;
2524   }
2525 
2526 
2527 // Change font description from a string
setFont(const FXString & string)2528 FXbool FXFont::setFont(const FXString& string){
2529   FXuint size,weight,slant,setwidth,encoding,hh;
2530   FXchar face[256];
2531   FXint len;
2532 
2533   // Initialize
2534   wantedName=FXString::null;
2535   wantedSize=0;
2536   wantedWeight=0;
2537   wantedSlant=0;
2538   wantedSetwidth=0;
2539   wantedEncoding=0;
2540   hints=0;
2541 
2542   // Non-empty name
2543   if(!string.empty()){
2544 
2545     // Try to match old format
2546     if(string.scan("[%[^]]] %u %u %u %u %u %u",face,&size,&weight,&slant,&encoding,&setwidth,&hh)==7){
2547       wantedName=face;
2548       wantedSize=size;
2549       wantedWeight=weight;
2550       wantedSlant=slant;
2551       wantedSetwidth=setwidth;
2552       wantedEncoding=encoding;
2553       hints=hh;
2554       return TRUE;
2555       }
2556 
2557     // Check for X11 font
2558     len=string.find(',');
2559     if(len<0){
2560       wantedName=string;
2561       hints|=FONTHINT_X11;
2562       return TRUE;
2563       }
2564 
2565     // Normal font description
2566     wantedName=string.left(len);
2567     wantedSize=FXUIntVal(string.section(',',1));
2568     wantedWeight=findbyname(weighttable,ARRAYNUMBER(weighttable),string.section(',',2));
2569     wantedSlant=findbyname(slanttable,ARRAYNUMBER(slanttable),string.section(',',3));
2570     wantedSetwidth=findbyname(setwidthtable,ARRAYNUMBER(setwidthtable),string.section(',',4));
2571     wantedEncoding=findbyname(encodingtable,ARRAYNUMBER(encodingtable),string.section(',',5));
2572     hints=FXUIntVal(string.section(',',6));
2573 
2574     return TRUE;
2575     }
2576   return FALSE;
2577   }
2578 
2579 
2580 
2581 // Return the font description as a string; keep it as simple
2582 // as possible by dropping defaulted fields at the end.
getFont() const2583 FXString FXFont::getFont() const {
2584   FXString string=wantedName;
2585 
2586   // Raw X11 is only the name
2587   if(!(hints&FONTHINT_X11)){
2588 
2589     // Append size
2590     string.append(',');
2591     string.append(FXStringVal(wantedSize));
2592 
2593     // Weight and other stuff
2594     if(wantedWeight || wantedSlant || wantedSetwidth || wantedEncoding || hints){
2595 
2596       // Append weight
2597       string.append(',');
2598       string.append(findbyvalue(weighttable,ARRAYNUMBER(weighttable),wantedWeight));
2599 
2600       // Slant and other stuff
2601       if(wantedSlant || wantedSetwidth || wantedEncoding || hints){
2602 
2603         // Append slant
2604         string.append(',');
2605         string.append(findbyvalue(slanttable,ARRAYNUMBER(slanttable),wantedSlant));
2606 
2607         // Setwidth and other stuff
2608         if(wantedSetwidth || wantedEncoding || hints){
2609 
2610           // Append set width
2611           string.append(',');
2612           string.append(findbyvalue(setwidthtable,ARRAYNUMBER(setwidthtable),wantedSetwidth));
2613 
2614           // Encoding and other stuff
2615           if(wantedEncoding || hints){
2616 
2617             // Append encoding
2618             string.append(',');
2619             string.append(findbyvalue(encodingtable,ARRAYNUMBER(encodingtable),wantedEncoding));
2620 
2621             // Hints
2622             if(hints){
2623 
2624               // Append hint flags
2625               string.append(',');
2626               string.append(FXStringVal(hints));
2627               }
2628             }
2629           }
2630         }
2631       }
2632     }
2633   return string;
2634   }
2635 
2636 
2637 // Thanks to Yakubenko Maxim <max@tiki.sio.rssi.ru> the patch to the
2638 // functions below; the problem was that spaces may occur in the font
2639 // name (e.g. Courier New).  The scanset method will simply parse the
2640 // string, including any spaces, until the matching bracket.
2641 
2642 // Parse font description DEPRECATED
fxparsefontdesc(FXFontDesc & fontdesc,const FXchar * string)2643 FXbool fxparsefontdesc(FXFontDesc& fontdesc,const FXchar* string){
2644   return string && (sscanf(string,"[%[^]]] %u %u %u %u %u %u",fontdesc.face,&fontdesc.size,&fontdesc.weight,&fontdesc.slant,&fontdesc.encoding,&fontdesc.setwidth,&fontdesc.flags)==7);
2645   }
2646 
2647 
2648 // Unparse font description DEPRECATED
fxunparsefontdesc(FXchar * string,const FXFontDesc & fontdesc)2649 FXbool fxunparsefontdesc(FXchar *string,const FXFontDesc& fontdesc){
2650   sprintf(string,"[%s] %u %u %u %u %u %u",fontdesc.face,fontdesc.size,fontdesc.weight,fontdesc.slant,fontdesc.encoding,fontdesc.setwidth,fontdesc.flags);
2651   return TRUE;
2652   }
2653 
2654 
2655 /*******************************************************************************/
2656 
2657 
2658 // Save font to stream
save(FXStream & store) const2659 void FXFont::save(FXStream& store) const {
2660   FXId::save(store);
2661   store << wantedName;
2662   store << wantedSize;
2663   store << wantedWeight;
2664   store << wantedSlant;
2665   store << wantedSetwidth;
2666   store << wantedEncoding;
2667   store << hints;
2668   }
2669 
2670 
2671 // Load font from stream; create() should be called later
load(FXStream & store)2672 void FXFont::load(FXStream& store){
2673   FXId::load(store);
2674   store >> wantedName;
2675   store >> wantedSize;
2676   store >> wantedWeight;
2677   store >> wantedSlant;
2678   store >> wantedSetwidth;
2679   store >> wantedEncoding;
2680   store >> hints;
2681   }
2682 
2683 
2684 // Clean up
~FXFont()2685 FXFont::~FXFont(){
2686   FXTRACE((100,"FXFont::~FXFont %p\n",this));
2687   destroy();
2688   }
2689 
2690 }
2691