1 /********************************************************************************
2 *                                                                               *
3 *                               F o n t   O b j e c t                           *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (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                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxascii.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXMutex.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXElement.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXException.h"
36 #include "FXRegion.h"
37 #include "FXStringDictionary.h"
38 #include "FXSettings.h"
39 #include "FXRegistry.h"
40 #include "FXFont.h"
41 #include "FXEvent.h"
42 #include "FXWindow.h"
43 #include "FXDCWindow.h"
44 #include "FXApp.h"
45 
46 /*
47   Notes:
48 
49   - Interpretation of the hints:
50 
51       0                    No preference for pitch
52       FXFont::Fixed        If specified, match for fixed pitch fonts are strongly preferred
53       FXFont::Variable     If specified, match for variable pitch font strongly preferred
54 
55       0                    No hints given
56       FXFont::Decorative   Ye Olde Fonte
57       FXFont::Modern       Monospace fonts such as courier and so on
58       FXFont::Roman        Serif font such as times
59       FXFont::Script       Cursive font/script
60       FXFont::Swiss        Sans serif font such as swiss, helvetica, arial
61       FXFont::System       Raster based fonts, typically monospaced
62 
63       FXFont::X11          Force X11 raw font specification
64 
65       FXFont::Scalable     Strong emphasis on scalable fonts; under Windows, this means
66                            TrueType fonts are desired
67 
68       FXFont::Polymorphic  Strong emphasis on polymorphic fonts; under Windows, this means
69                            TrueType fonts desired also
70 
71   - FONTENCODING_DEFAULT means we prefer the fonts for the current locale;
72     currently, this is hardwired to iso8859-1 until we have some means of
73     determining the preferred encoding from the locale.
74 
75   - FXFont::Italic is a cursive typeface for some fonts; FXFont::Oblique is the same
76     basic font written at an angle; for many fonts, FXFont::Italic and FXFont::Oblique
77     means pretty much the same thing.  When matching, FXFont::Italic and FXFont::Oblique
78     are considered closer to each other than FXFont::Straight.
79 
80   - A weight value of 0 indicates preference for non-bold font.
81 
82   - XFontStruct.ascent+XFontStruct.descent is the height of the font, as far as line
83     spacing goes.  XFontStruct.max_bounds.ascent+XFontStruct.max_bounds.descent is
84     larger, as some characters can apparently extend beyond ascent or descent!!
85 
86   - Registry section FONTSUBSTITUTIONS can be used to map typeface names to platform
87     specific typeface names:
88 
89         [FONTSUBSTITUTIONS]
90         arial = helvetica
91         swiss = helvetica
92 
93     This allows you to change fonts in programs with hard-wired fonts.
94 
95   - Text txfm matrix [a b c d] premultiplies.
96 
97   - Should we perhaps build our own tables of font metrics? This might make
98     things simpler for the advanced stuff, and be conceivably a lot faster
99     under MS-Windows [no need to SelectObject() all the time just to get some
100     info; also, this could be useful in case the drawing surface is not a
101     window].
102 
103   - FOR THE MOMENT we're creating a dummy DC to keep the font locked into the GDI
104     for MUCH quicker access to text metrics.  Soon however we want to just build
105     our own font metrics tables and determine the metrics entirely with client-side
106     code.  This will [predictably] be the fastest possible method as it will not
107     involve context switches...
108 
109   - Matching algorithm slightly favors bitmapped fonts over scalable ones [as the
110     latter may not be optimized easthetically; also, the matching algorithm should
111     not weight resolution as much.
112 
113   - UNICODE means registry and encoding are set to iso10646-1
114 
115   - More human-readable font strings (e.g. registry):
116 
117        family [foundry],size,weight,slant,setwidth,encoding,hints
118 
119     For example:
120 
121        times [urw],120,bold,i,normal,iso8859-1,0
122 
123     Note that the size is in decipoints!
124 
125   - Get encoding from locale (see X11).
126 
127   - ix|xi
128 */
129 
130 
131 
132 /*******************************************************************************/
133 
134 using namespace FX;
135 
136 
137 namespace FX {
138 
139 
140 static const FXint LEAD_OFFSET=0xD800-(0x10000>>10);
141 static const FXint TAIL_OFFSET=0xDC00;
142 
143 
144 extern FXAPI FXint __snprintf(FXchar* string,FXint length,const FXchar* format,...);
145 
146 #if defined(WIN32) /////////////////////////// WIN32 ////////////////////////////
147 
148 
149 // Character set encoding
FXFontEncoding2CharSet(FXuint encoding)150 static BYTE FXFontEncoding2CharSet(FXuint encoding){
151   switch(encoding){
152     case FONTENCODING_DEFAULT: return DEFAULT_CHARSET;
153     case FONTENCODING_TURKISH: return TURKISH_CHARSET;
154     case FONTENCODING_BALTIC: return BALTIC_CHARSET;
155     case FONTENCODING_CYRILLIC: return RUSSIAN_CHARSET;
156     case FONTENCODING_ARABIC: return ARABIC_CHARSET;
157     case FONTENCODING_GREEK: return GREEK_CHARSET;
158     case FONTENCODING_HEBREW: return HEBREW_CHARSET;
159     case FONTENCODING_THAI: return THAI_CHARSET;
160     case FONTENCODING_EASTEUROPE: return EASTEUROPE_CHARSET;
161     case FONTENCODING_USASCII: return ANSI_CHARSET;
162 //    case FONTENCODING_UNICODE: return ANSI_CHARSET;
163     }
164   return DEFAULT_CHARSET;
165   }
166 
167 
168 // Character set encoding
CharSet2FXFontEncoding(BYTE lfCharSet)169 static FXuint CharSet2FXFontEncoding(BYTE lfCharSet){
170   switch(lfCharSet){
171     case ANSI_CHARSET: return FONTENCODING_USASCII;
172     case ARABIC_CHARSET: return FONTENCODING_ARABIC;
173     case BALTIC_CHARSET: return FONTENCODING_BALTIC;
174     case CHINESEBIG5_CHARSET: return FONTENCODING_DEFAULT;
175     case DEFAULT_CHARSET: return FONTENCODING_DEFAULT;
176     case EASTEUROPE_CHARSET: return FONTENCODING_EASTEUROPE;
177     case GB2312_CHARSET: return FONTENCODING_DEFAULT;
178     case GREEK_CHARSET: return FONTENCODING_GREEK;
179 #if !defined (__WATCOMC__) || (__WATCOMC__ >= 1200)
180     case HANGUL_CHARSET: return FONTENCODING_DEFAULT;
181 #endif
182     case HEBREW_CHARSET: return FONTENCODING_HEBREW;
183     case MAC_CHARSET: return FONTENCODING_DEFAULT;
184     case OEM_CHARSET: return FONTENCODING_DEFAULT;
185     case SYMBOL_CHARSET: return FONTENCODING_DEFAULT;
186     case RUSSIAN_CHARSET: return FONTENCODING_CYRILLIC;
187     case SHIFTJIS_CHARSET: return FONTENCODING_DEFAULT;
188     case THAI_CHARSET: return FONTENCODING_THAI;
189     case TURKISH_CHARSET: return FONTENCODING_TURKISH;
190     }
191   return FONTENCODING_DEFAULT;
192   }
193 
194 
195 // Try find matching font
match(const FXString & wantfamily,const FXString & wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res)196 void* FXFont::match(const FXString& wantfamily,const FXString& wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res){
197   FXTRACE((150,"wantfamily=%s wantforge=%s wantsize=%d wantweight=%d wantslant=%d wantsetwidth=%d wantencoding=%d wanthints=%d res=%d\n",wantfamily.text(),wantforge.text(),wantsize,wantweight,wantslant,wantsetwidth,wantencoding,wanthints,res));
198   TEXTMETRIC *font;
199   LOGFONT lf;
200   FXchar buffer[256];
201 
202   // Hang on to this for text metrics functions
203   dc=CreateCompatibleDC(NULL);
204 
205   // Now fill in the fields
206   lf.lfHeight=-MulDiv(wantsize,GetDeviceCaps((HDC)dc,LOGPIXELSY),720);
207   lf.lfWidth=0;
208   if(wanthints&FXFont::Rotatable){
209     lf.lfEscapement=(angle*10)/64;
210     lf.lfOrientation=(angle*10)/64;
211     }
212   else{
213     lf.lfEscapement=0;
214     lf.lfOrientation=0;
215     }
216   lf.lfWeight=wantweight*10;
217   if((wantslant==FXFont::Italic) || (wantslant==FXFont::Oblique))
218     lf.lfItalic=true;
219   else
220     lf.lfItalic=false;
221   lf.lfUnderline=false;
222   lf.lfStrikeOut=false;
223 
224   // Character set encoding
225   lf.lfCharSet=FXFontEncoding2CharSet(wantencoding);
226 
227   // Other hints
228   lf.lfOutPrecision=OUT_DEFAULT_PRECIS;
229   if(wanthints&FXFont::System) lf.lfOutPrecision=OUT_RASTER_PRECIS;
230   if(wanthints&FXFont::Scalable) lf.lfOutPrecision=OUT_TT_PRECIS;
231   if(wanthints&FXFont::Polymorphic) lf.lfOutPrecision=OUT_TT_PRECIS;
232 
233   // Clip precision
234   lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;
235 
236   // Quality
237   lf.lfQuality=DEFAULT_QUALITY;
238 
239   // Pitch and Family
240   lf.lfPitchAndFamily=0;
241 
242   // Pitch
243   if(wanthints&FXFont::Fixed) lf.lfPitchAndFamily|=FIXED_PITCH;
244   else if(wanthints&FXFont::Variable) lf.lfPitchAndFamily|=VARIABLE_PITCH;
245   else lf.lfPitchAndFamily|=DEFAULT_PITCH;
246 
247   // Family
248   if(wanthints&FXFont::Decorative) lf.lfPitchAndFamily|=FF_DECORATIVE;
249   else if(wanthints&FXFont::Modern) lf.lfPitchAndFamily|=FF_MODERN;
250   else if(wanthints&FXFont::Roman) lf.lfPitchAndFamily|=FF_ROMAN;
251   else if(wanthints&FXFont::Script) lf.lfPitchAndFamily|=FF_SCRIPT;
252   else if(wanthints&FXFont::Swiss) lf.lfPitchAndFamily|=FF_SWISS;
253   else lf.lfPitchAndFamily|=FF_DONTCARE;
254 
255   // Font substitution
256 #ifdef UNICODE
257   utf2ncs(lf.lfFaceName,wantfamily.text(),LF_FACESIZE);
258 #else
259   fxstrlcpy(lf.lfFaceName,wantfamily.text(),LF_FACESIZE);
260 #endif
261 
262   // Here we go!
263   xid=CreateFontIndirect(&lf);
264 
265   // Uh-oh, we failed
266   if(!xid) return NULL;
267 
268   // Obtain text metrics
269   if(!callocElms(font,1)) return NULL;
270 
271   SelectObject((HDC)dc,xid);
272   GetTextMetrics((HDC)dc,(TEXTMETRIC*)font);
273 
274   // Get actual face name
275   GetTextFaceA((HDC)dc,sizeof(buffer),buffer);
276   actualName=buffer;
277   actualSize=MulDiv(((TEXTMETRIC*)font)->tmHeight,720,GetDeviceCaps((HDC)dc,LOGPIXELSY));
278   actualWeight=((TEXTMETRIC*)font)->tmWeight/10;
279   actualSlant=((TEXTMETRIC*)font)->tmItalic?FXFont::Italic:FXFont::Straight;
280   actualSetwidth=0;
281   actualEncoding=CharSet2FXFontEncoding(((TEXTMETRIC*)font)->tmCharSet);
282 
283   // Return it
284   return font;
285   }
286 
287 
288 #elif defined(HAVE_XFT_H) /////////////////////// XFT ///////////////////////////
289 
290 
291 // Access to display
292 #define DISPLAY(app)      ((Display*)((app)->display))
293 
294 // For Fontconfig 1.0.2
295 #ifndef FC_WEIGHT_THIN
296 #define FC_WEIGHT_THIN              0
297 #undef FC_WEIGHT_LIGHT
298 #define FC_WEIGHT_LIGHT             50
299 #endif
300 #ifndef FC_WEIGHT_EXTRALIGHT
301 #define FC_WEIGHT_EXTRALIGHT        40
302 #endif
303 #ifndef FC_WEIGHT_NORMAL
304 #define FC_WEIGHT_NORMAL            80
305 #endif
306 #ifndef FC_WEIGHT_EXTRABOLD
307 #define FC_WEIGHT_EXTRABOLD         205
308 #endif
309 
310 
311 // From FOX weight to fontconfig weight
weight2FcWeight(FXint weight)312 static FXint weight2FcWeight(FXint weight){
313   switch(weight){
314     case FXFont::Thin:      return FC_WEIGHT_THIN;
315     case FXFont::ExtraLight:return FC_WEIGHT_EXTRALIGHT;
316     case FXFont::Light:     return FC_WEIGHT_LIGHT;
317     case FXFont::Normal:    return FC_WEIGHT_NORMAL;
318     case FXFont::Medium:    return FC_WEIGHT_MEDIUM;
319     case FXFont::DemiBold:  return FC_WEIGHT_DEMIBOLD;
320     case FXFont::Bold:      return FC_WEIGHT_BOLD;
321     case FXFont::ExtraBold: return FC_WEIGHT_EXTRABOLD;
322     case FXFont::Black:     return FC_WEIGHT_BLACK;
323     }
324   return FC_WEIGHT_NORMAL;
325   }
326 
327 
328 // From fontconfig weight to FOX weight
fcWeight2Weight(FXint fcWeight)329 static FXint fcWeight2Weight(FXint fcWeight){
330   switch(fcWeight){
331     case FC_WEIGHT_THIN:      return FXFont::Thin;
332     case FC_WEIGHT_EXTRALIGHT:return FXFont::ExtraLight;
333     case FC_WEIGHT_LIGHT:     return FXFont::Light;
334     case FC_WEIGHT_NORMAL:    return FXFont::Normal;
335     case FC_WEIGHT_MEDIUM:    return FXFont::Medium;
336     case FC_WEIGHT_DEMIBOLD:  return FXFont::DemiBold;
337     case FC_WEIGHT_BOLD:      return FXFont::Bold;
338     case FC_WEIGHT_EXTRABOLD: return FXFont::ExtraBold;
339     case FC_WEIGHT_BLACK:     return FXFont::Black;
340     }
341   return FXFont::Normal;
342   }
343 
344 
345 // From FOX setwidth to fontconfig setwidth
setWidth2FcSetWidth(FXint setwidth)346 static FXint setWidth2FcSetWidth(FXint setwidth){
347 #ifdef FC_WIDTH
348   switch(setwidth){
349     case FXFont::UltraCondensed:return FC_WIDTH_ULTRACONDENSED;
350     case FXFont::ExtraCondensed:return FC_WIDTH_EXTRACONDENSED;
351     case FXFont::Condensed:     return FC_WIDTH_CONDENSED;
352     case FXFont::SemiCondensed: return FC_WIDTH_SEMICONDENSED;
353     case FXFont::NonExpanded:        return FC_WIDTH_NORMAL;
354     case FXFont::SemiExpanded:  return FC_WIDTH_SEMIEXPANDED;
355     case FXFont::Expanded:      return FC_WIDTH_EXPANDED;
356     case FXFont::ExtraExpanded: return FC_WIDTH_EXTRAEXPANDED;
357     case FXFont::UltraExpanded: return FC_WIDTH_ULTRAEXPANDED;
358     }
359   return FC_WIDTH_NORMAL;
360 #else
361   return 0;
362 #endif
363   }
364 
365 
366 // From fontconfig setwidth to FOX setwidth
fcSetWidth2SetWidth(FXint fcSetWidth)367 static FXint fcSetWidth2SetWidth(FXint fcSetWidth){
368 #ifdef FC_WIDTH
369   switch(fcSetWidth){
370     case FC_WIDTH_ULTRACONDENSED:return FXFont::UltraCondensed;
371     case FC_WIDTH_EXTRACONDENSED:return FXFont::ExtraCondensed;
372     case FC_WIDTH_CONDENSED:     return FXFont::Condensed;
373     case FC_WIDTH_SEMICONDENSED: return FXFont::SemiCondensed;
374     case FC_WIDTH_NORMAL:        return FXFont::NonExpanded;
375     case FC_WIDTH_SEMIEXPANDED:  return FXFont::SemiExpanded;
376     case FC_WIDTH_EXPANDED:      return FXFont::Expanded;
377     case FC_WIDTH_EXTRAEXPANDED: return FXFont::ExtraExpanded;
378     case FC_WIDTH_ULTRAEXPANDED: return FXFont::UltraExpanded;
379     }
380 #endif
381   return FXFont::NonExpanded;
382   }
383 
384 
385 // From FOX slant to fontconfig slant
slant2FcSlant(FXint slant)386 static FXint slant2FcSlant(FXint slant){
387   switch(slant){
388     case FXFont::Straight: return FC_SLANT_ROMAN;
389     case FXFont::Italic: return FC_SLANT_ITALIC;
390     case FXFont::Oblique: return FC_SLANT_OBLIQUE;
391     case FXFont::ReverseItalic: return FC_SLANT_ITALIC;         // No equivalent FC value
392     case FXFont::ReverseOblique: return FC_SLANT_OBLIQUE;       // No equivalent FC value
393     }
394   return FC_SLANT_ROMAN;
395   }
396 
397 
398 // From fontconfig slant to FOX slant
fcSlant2Slant(FXint fcSlant)399 static FXint fcSlant2Slant(FXint fcSlant){
400   switch(fcSlant){
401     case FC_SLANT_ROMAN:  return FXFont::Straight;
402     case FC_SLANT_ITALIC: return FXFont::Italic;
403     case FC_SLANT_OBLIQUE:return FXFont::Oblique;
404     }
405   return FXFont::Straight;
406   }
407 
408 
409 // Try find matching font
match(const FXString & wantfamily,const FXString & wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res)410 void* FXFont::match(const FXString& wantfamily,const FXString& wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res){
411   const FXchar *rgba=getApp()->reg().readStringEntry("Xft","rgba","unknown");
412   const FXchar *hs=getApp()->reg().readStringEntry("Xft","hintstyle","full");
413   FXbool     fc_hinting=getApp()->reg().readBoolEntry("Xft","hinting",true);
414   FXbool     fc_autohint=getApp()->reg().readBoolEntry("Xft","autohint",false);
415   FXbool     fc_antialias=getApp()->reg().readBoolEntry("Xft","antialias",true);
416   FXint      fc_rgba=FC_RGBA_UNKNOWN;
417 #ifdef FC_HINT_STYLE
418   FXint      fc_hintstyle=FC_HINT_FULL;
419 #endif
420   int        pp,sw,wt,sl;
421   double     a,s,c,sz;
422   FcPattern *pattern,*p;
423   FcChar8   *fam,*fdy;
424   FcCharSet *charset;
425   XftFont   *fnt;
426   FcResult   result;
427   FcBool     sc;
428   FcMatrix   matrix;
429 
430   FXTRACE((150,"wantfamily=%s wantforge=%s wantsize=%d wantweight=%d wantslant=%d wantsetwidth=%d wantencoding=%d wanthints=%d res=%d\n",wantfamily.text(),wantforge.text(),wantsize,wantweight,wantslant,wantsetwidth,wantencoding,wanthints,res));
431 
432   // Create pattern object
433   pattern=FcPatternCreate();
434 
435   // RGBA color order hint
436   if(rgba[0]=='u') fc_rgba=FC_RGBA_UNKNOWN;
437   else if(rgba[0]=='r') fc_rgba=FC_RGBA_RGB;
438   else if(rgba[0]=='b') fc_rgba=FC_RGBA_BGR;
439   else if(rgba[0]=='v' && rgba[1]=='r') fc_rgba=FC_RGBA_VRGB;
440   else if(rgba[0]=='v' && rgba[1]=='b') fc_rgba=FC_RGBA_VBGR;
441 
442 #ifdef FC_HINT_STYLE
443   if(hs[0]=='s') fc_hintstyle=FC_HINT_SLIGHT;
444   else if(hs[0]=='m') fc_hintstyle=FC_HINT_SLIGHT;
445   else if(hs[0]=='f') fc_hintstyle=FC_HINT_FULL;
446 #endif
447 
448   // Set additional hints
449   FcPatternAddBool(pattern,FC_HINTING,fc_hinting);
450   FcPatternAddBool(pattern,FC_ANTIALIAS,fc_antialias);
451   FcPatternAddBool(pattern,FC_AUTOHINT,fc_autohint);
452   FcPatternAddInteger(pattern,FC_RGBA,fc_rgba);
453 #ifdef FC_HINT_STYLE
454   FcPatternAddInteger(pattern,FC_HINT_STYLE,fc_hintstyle);
455 #endif
456 
457   // Set family
458   if(!wantfamily.empty()){
459     FcPatternAddString(pattern,FC_FAMILY,(const FcChar8*)wantfamily.text());
460     }
461 
462   // Set foundry
463   if(!wantforge.empty()){
464     FcPatternAddString(pattern,FC_FOUNDRY,(const FcChar8*)wantforge.text());
465     }
466 
467   // Set pixel size, based on given screen res and desired point size
468   if(wantsize!=0){
469     FcPatternAddDouble(pattern,FC_PIXEL_SIZE,(res*wantsize)/720.0);
470     }
471 
472   // Set font weight
473   if(wantweight!=0){
474     FcPatternAddInteger(pattern,FC_WEIGHT,weight2FcWeight(wantweight));
475     }
476 
477   // Set slant
478   if(wantslant!=0){
479     FcPatternAddInteger(pattern,FC_SLANT,slant2FcSlant(wantslant));
480     }
481 
482 #ifdef FC_WIDTH
483   // Set setwidth
484   if(wantsetwidth!=0){
485     FcPatternAddInteger(pattern,FC_WIDTH,setWidth2FcSetWidth(wantsetwidth));
486     }
487 #endif
488 
489   // Set encoding
490   if(wantencoding!=FONTENCODING_DEFAULT){                                       // FIXME
491 //    FcCharSet* charSet=FcCharSetCreate();
492 //    encoding2FcCharSet((void*)charSet, (FXFontEncoding)encoding);
493 //    FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
494 //    FcCharSetDestroy(charSet);
495     }
496 
497   // Set pitch
498   if(wanthints&FXFont::Fixed){
499     FcPatternAddInteger(pattern,FC_SPACING,FC_MONO);
500     }
501   else if(wanthints&FXFont::Variable){
502     FcPatternAddInteger(pattern,FC_SPACING,FC_PROPORTIONAL);
503     }
504 
505   // Scalable font hint; also set if we want rotation
506   if(wanthints&(FXFont::Scalable|FXFont::Rotatable)){
507     FcPatternAddBool(pattern,FC_SCALABLE,true);
508     }
509 
510   // Always set matrix if rotatable
511   if(wanthints&FXFont::Rotatable){
512     a=0.00027270769562411399179*angle;
513     c=Math::cos(a);
514     s=Math::sin(a);
515     matrix.xx=c; matrix.xy=-s;
516     matrix.yx=s; matrix.yy=c;
517     FcPatternAddMatrix(pattern,FC_MATRIX,&matrix);
518     }
519 
520   // Pattern substitutions
521   FcConfigSubstitute(0,pattern,FcMatchPattern);
522   FcDefaultSubstitute(pattern);
523 
524   // Find pattern matching a font
525   p=FcFontMatch(0,pattern,&result);
526   if(!p) return NULL;
527 
528   // Get name and foundry
529   if(FcPatternGetString(p,FC_FAMILY,0,&fam)==FcResultMatch){
530     actualName=(const FXchar*)fam;
531     if(FcPatternGetString(p,FC_FOUNDRY,0,&fdy)==FcResultMatch){
532       actualName.append(" [");
533       actualName.append((const FXchar*)fdy);
534       actualName.append("]");
535       }
536     }
537 
538 #ifdef FC_WIDTH
539   // Get setwidth
540   if(FcPatternGetInteger(p,FC_WIDTH,0,&sw)==FcResultMatch){
541     actualSetwidth=fcSetWidth2SetWidth(sw);
542     }
543 #endif
544 
545   // Get weight
546   if(FcPatternGetInteger(p,FC_WEIGHT,0,&wt)==FcResultMatch){
547     actualWeight=fcWeight2Weight(wt);
548     }
549 
550   // Get slant
551   if(FcPatternGetInteger(p,FC_SLANT,0,&sl)==FcResultMatch){
552     actualSlant=fcSlant2Slant(sl);
553     }
554 
555   // Get pitch
556   if(FcPatternGetInteger(p,FC_SPACING,0,&pp)==FcResultMatch){
557     flags&=~(FXFont::Fixed|FXFont::Variable);
558 //    if(pp==FC_MONO || pp==FC_DUAL || pp==FC_CHARCELL) flags|=FXFont::Fixed;
559     if(pp==FC_MONO || pp==FC_CHARCELL) flags|=FXFont::Fixed;
560     else if(pp==FC_PROPORTIONAL) flags|=FXFont::Variable;
561     }
562 
563   // Get scalable flag
564   if(FcPatternGetBool(p,FC_SCALABLE,0,&sc)==FcResultMatch){
565     flags=sc?(flags|FXFont::Scalable):(flags&~FXFont::Scalable);
566     }
567 
568   // Get pixel size and work it back to deci-points using given screen res
569   if(FcPatternGetDouble(p,FC_PIXEL_SIZE,0,&sz)==FcResultMatch){
570     actualSize=(int)((720.0*sz)/res);
571     }
572 
573   // Get charset
574   if(FcPatternGetCharSet(p,FC_CHARSET,0,&charset)==FcResultMatch){      // FIXME
575     }
576 
577   // Get the encoding
578   actualEncoding=FONTENCODING_UNICODE;
579 
580   // Open font
581   fnt=XftFontOpenPattern(DISPLAY(getApp()),p);
582   xid=(FXID)fnt;
583 
584   // Destroy pattern
585   FcPatternDestroy(pattern);
586 
587   return fnt;
588   }
589 
590 
591 #else ///////////////////////////////// XLFD ////////////////////////////////////
592 
593 
594 #define SGN(x)        ((x)<-0.0005?"~":"")
595 #define DISPLAY(app)  ((Display*)((app)->display))
596 
597 
598 // Convert text to font weight
xlfdWeight(const FXchar * text)599 static FXuint xlfdWeight(const FXchar* text){
600   FXchar c1=Ascii::toLower(text[0]);
601   FXchar c2=Ascii::toLower(text[1]);
602   if(c1=='l' && c2=='i') return FXFont::Light;
603   if(c1=='o' && c2=='u') return FXFont::Light;
604   if(c1=='s' && c2=='h') return FXFont::Light;
605   if(c1=='n' && c2=='o') return FXFont::Normal;
606   if(c1=='r' && c2=='e') return FXFont::Normal;
607   if(c1=='m' && c2=='e') return FXFont::Medium;
608   if(c1=='d' && c2=='e') return FXFont::DemiBold;
609   if(c1=='s' && c2=='e') return FXFont::DemiBold;
610   if(c1=='b' && c2=='o') return FXFont::Bold;
611   if(c1=='b' && c2=='l') return FXFont::Black;
612   return 0;
613   }
614 
615 
616 // Convert text to slant
xlfdSlant(const FXchar * text)617 static FXuint xlfdSlant(const FXchar* text){
618   FXchar c1=Ascii::toLower(text[0]);
619   FXchar c2=Ascii::toLower(text[1]);
620   if(c1=='i') return FXFont::Italic;
621   if(c1=='o') return FXFont::Oblique;
622   if(c1=='r' && c2=='i') return FXFont::ReverseItalic;
623   if(c1=='r' && c2=='o') return FXFont::ReverseOblique;
624   if(c1=='r') return FXFont::Straight;
625   return 0;
626   }
627 
628 
629 // Convert text to setwidth
xlfdSetwidth(const FXchar * text)630 static FXuint xlfdSetwidth(const FXchar* text){
631   if(text[0]=='m') return FXFont::NonExpanded;
632   if(text[0]=='w') return FXFont::ExtraExpanded;
633   if(text[0]=='r') return FXFont::NonExpanded;
634   if(text[0]=='c') return FXFont::Condensed;
635   if(text[0]=='n'){
636     if(text[1]=='a') return FXFont::Condensed;
637     if(text[1]=='o') return FXFont::NonExpanded;
638     return 0;
639     }
640   if(text[0]=='e' && text[1]=='x' && text[2]=='p') return FXFont::Expanded;
641   if(text[0]=='e' && text[1]=='x' && text[2]=='t' && text[3]=='r' && text[4]=='a'){
642     if(text[5]=='c') return FXFont::ExtraCondensed;
643     if(text[5]=='e') return FXFont::ExtraExpanded;
644     return 0;
645     }
646   if(text[0]=='u' && text[1]=='l' && text[2]=='t' && text[3]=='r' && text[4]=='a'){
647     if(text[5]=='c') return FXFont::UltraCondensed;
648     if(text[5]=='e') return FXFont::UltraExpanded;
649     return 0;
650     }
651   if((text[0]=='s' || text[0]=='d') && text[1]=='e' && text[2]=='m' && text[3]=='i'){
652     if(text[5]=='c') return FXFont::SemiCondensed;
653     if(text[5]=='e') return FXFont::SemiExpanded;
654     return 0;
655     }
656   return 0;
657   }
658 
659 
660 // Convert pitch to flags
xlfdPitch(const FXchar * text)661 static FXuint xlfdPitch(const FXchar* text){
662   FXchar c=Ascii::toLower(text[0]);
663   if(c=='p') return FXFont::Variable;
664   if(c=='m' || c=='c') return FXFont::Fixed;
665   return 0;
666   }
667 
668 
669 // Convert fields to scalable flag
xlfdScalable(const FXchar * pixelsize,const FXchar * pointsize,const FXchar * average)670 static FXuint xlfdScalable(const FXchar *pixelsize,const FXchar *pointsize,const FXchar* average){
671   if(pixelsize[0]=='[' && pointsize[0]=='[' && average[0]=='0') return FXFont::Scalable;
672   if(pixelsize[0]=='0' && pointsize[0]=='0' && average[0]=='0') return FXFont::Scalable;
673   return 0;
674   }
675 
676 
677 // Convert fields to rotatable flag
xlfdRotatable(const FXchar * pixelsize,const FXchar * pointsize)678 static FXuint xlfdRotatable(const FXchar *pixelsize,const FXchar *pointsize){
679   if(pixelsize[0]=='[' && pointsize[0]=='[') return FXFont::Rotatable;
680   return 0;
681   }
682 
683 
684 // Convert fields to rotatable flag
xlfdPolymorph(const FXchar * weight,const FXchar * slant,const FXchar * setwidth,const FXchar * addstyle)685 static FXuint xlfdPolymorph(const FXchar *weight,const FXchar* slant,const FXchar *setwidth,const FXchar* addstyle){
686   if(weight[0]=='0' || slant[0]=='0' || setwidth[0]=='0' || addstyle[0]=='0') return FXFont::Polymorphic;
687   return 0;
688   }
689 
690 
691 // Determine encoding; these codes should tie into the codec list in some way
xlfdEncoding(const FXchar * text)692 static FXuint xlfdEncoding(const FXchar* text){
693   if((text[0]=='i' || text[0]=='I') && (text[1]=='s' || text[1]=='S') && (text[2]=='o' || text[2]=='O')){
694     if(text[3]=='8' && text[4]=='8' && text[5]=='5' && text[6]=='9' && text[7]=='-'){
695       return FONTENCODING_ISO_8859_1+atoi(text+8)-1;    // iso8859-XX
696       }
697     if(text[3]=='1' && text[4]=='0' &&text[5]=='6' && text[6]=='4' && text[7]=='6' && text[8]=='-' && text[9]=='1'){
698       return FONTENCODING_UNICODE;                      // iso10646-1
699       }
700     return FONTENCODING_DEFAULT;
701     }
702   if((text[0]=='k' || text[0]=='K') && (text[1]=='o' || text[1]=='O') && (text[2]=='i' || text[2]=='I') && text[3]=='8'){
703     if(text[4]=='r' || text[4]=='R'){
704       return FONTENCODING_KOI8_R;                       // koi8r
705       }
706     if(text[4]=='u' || text[4]=='U'){                   // koi8u
707       return FONTENCODING_KOI8_U;
708       }
709     return FONTENCODING_KOI8;
710     }
711   if((text[0]=='m' || text[0]=='M') && (text[1]=='i' || text[1]=='I') && (text[2]=='c' || text[2]=='C') && (text[3]=='r' || text[3]=='R') && (text[4]=='o' || text[4]=='O') && (text[5]=='s' || text[5]=='S') && (text[6]=='o' || text[6]=='O') && (text[7]=='f' || text[7]=='F') && (text[8]=='t' || text[8]=='T') && text[9]=='-'){
712     if((text[10]=='c' || text[10]=='C') && (text[11]=='p' || text[11]=='P')){
713       return atoi(text+12);                             // microsoft-cpXXXX
714       }
715     return FONTENCODING_DEFAULT;
716     }
717   if((text[0]=='j' || text[0]=='J') && (text[1]=='i' || text[1]=='I') && (text[2]=='s' || text[2]=='S') && (text[3]=='x' || text[3]=='X')){
718     return FONTENCODING_DEFAULT;                        // jisx.XXXX.YYYY-Z FIXME
719     }
720   if((text[0]=='b' || text[0]=='B') && (text[1]=='i' || text[1]=='I') && (text[2]=='g' || text[2]=='G') && text[3]=='5'){
721     return FONTENCODING_DEFAULT;                        // big5XXX FIXME
722     }
723   if((text[0]=='k' || text[0]=='K') && (text[1]=='s' || text[1]=='S') && (text[2]=='c' || text[2]=='C')){
724     return FONTENCODING_DEFAULT;                        // kscXXX FIXME
725     }
726   if((text[0]=='g' || text[0]=='G') && (text[1]=='b' || text[1]=='B')){
727     return FONTENCODING_DEFAULT;                        // gbXXXX FIXME
728     }
729   return FONTENCODING_DEFAULT;
730   }
731 
732 
733 // Split XLFD into pieces
xlfdSplit(const char * fld[],char * font)734 static void xlfdSplit(const char *fld[],char* font){
735   fld[0]=fld[1]=fld[2]=fld[3]=fld[4]=fld[5]=fld[6]=fld[7]=fld[8]=fld[9]=fld[10]=fld[11]=fld[12]="";
736   if(*font=='-'){
737     fld[0]=++font;
738     for(int f=1; f<=12; f++){
739       while(*font && *font!='-') font++;
740       if(*font=='-') *font++='\0';
741       fld[f]=font;
742       }
743     }
744   else{
745     fld[1]=font;
746     }
747   }
748 
749 
750 // Return font name from a font possibly containing wildcards
xlfdFont(Display * dpy,const FXString & font)751 static FXString xlfdFont(Display *dpy,const FXString& font){
752   char **fontnames; int nfontnames;
753   FXString fontname(font);
754   if((fontnames=XListFonts(dpy,font.text(),1,&nfontnames))!=NULL){
755     fontname=fontnames[0];
756     XFreeFontNames(fontnames);
757     }
758   return fontname;
759   }
760 
761 
762 // Try find matching font
match(const FXString & wantfamily,const FXString & wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res)763 void* FXFont::match(const FXString& wantfamily,const FXString& wantforge,FXuint wantsize,FXuint wantweight,FXuint wantslant,FXuint wantsetwidth,FXuint wantencoding,FXuint wanthints,FXint res){
764   FXuint   encoding,weight,slant,setwidth,pitch,scalable,rotatable,polymorph,xres,yres,points,size;
765   FXint    bencoding,bweight,bslant,bsetwidth,bpitch,bscalable,brotatable,bpolymorph,bsize,bxres,byres;
766   FXint    dencoding,dweight,dslant,dsetwidth,dpitch,dscalable,drotatable,dpolymorph,dsize;
767   FXchar   candidate[256],xlfd[256];
768   FXchar **fontnames;
769   FXint    nfontnames,b,f;
770   const FXchar *field[13];
771   FXdouble c,s,a;
772   XFontStruct *fs;
773 
774   FXTRACE((150,"wantfamily=%s wantforge=%s wantsize=%d wantweight=%d wantslant=%d wantsetwidth=%d wantencoding=%d wanthints=%d res=%d\n",wantfamily.text(),wantforge.text(),wantsize,wantweight,wantslant,wantsetwidth,wantencoding,wanthints,res));
775 
776   // Get fonts matching the pattern
777   __snprintf(candidate,sizeof(candidate),"-%s-%s-*-*-*-*-*-%s-*-*-*-*-*-*",wantforge.empty()?"*":wantforge.text(),wantfamily.empty()?"*":wantfamily.text(),(hints&FXFont::Rotatable)?"[1 0 0 1]":"*");
778   fontnames=XListFonts(DISPLAY(getApp()),candidate,65535,&nfontnames);
779   if(fontnames && 0<nfontnames){
780 
781     b=-1;
782     bencoding=100000;
783     bweight=100000;
784     bslant=100000;
785     bsetwidth=100000;
786     bpitch=100000;
787     bscalable=100000;
788     brotatable=100000;
789     bpolymorph=100000;
790     bsize=100000;
791     bxres=res;
792     byres=res;
793 
794     // Match them
795     for(f=0; f<nfontnames; f++){
796 
797       //FXTRACE((1,"font=%s\n",fontnames[f]));
798 
799       // Break apart into fields
800       fxstrlcpy(candidate,fontnames[f],sizeof(candidate));
801       xlfdSplit(field,candidate);
802 
803       // Get info
804       weight=xlfdWeight(field[2]);
805       slant=xlfdSlant(field[3]);
806       setwidth=xlfdSetwidth(field[4]);
807       scalable=xlfdScalable(field[6],field[7],field[11]);
808       polymorph=xlfdPolymorph(field[2],field[3],field[4],field[5]);
809       rotatable=xlfdRotatable(field[6],field[7]);
810       points=atoi(field[7]);    // Deci-points
811       xres=atoi(field[8]);
812       yres=atoi(field[9]);
813       pitch=xlfdPitch(field[10]);
814       encoding=xlfdEncoding(field[12]);
815 
816       // The font can be rendered at any resolution, so render at actual device resolution
817       if(xres==0 && yres==0){
818         xres=res;
819         yres=res;
820         }
821 
822       // Encoding
823       if(wantencoding==FONTENCODING_DEFAULT){
824         dencoding=(encoding!=FONTENCODING_UNICODE);     // Want unicode if nothing else given
825         }
826       else{
827         dencoding=(encoding!=wantencoding);
828         }
829 
830       // Weight
831       if(wantweight){
832         dweight=Math::iabs(weight-wantweight);
833         }
834       else{
835         dweight=Math::iabs(weight-FXFont::Normal);
836         }
837 
838       // Slant
839       if(wantslant){
840         dslant=Math::iabs(slant-wantslant);
841         }
842       else{
843         dslant=Math::iabs(slant-FXFont::Straight);
844         }
845 
846       // Set width
847       if(wantsetwidth){
848         dsetwidth=Math::iabs(setwidth-wantsetwidth);
849         }
850       else{
851         dsetwidth=Math::iabs(setwidth-FXFont::NonExpanded);
852         }
853 
854       // Pitch
855       if(wanthints&FXFont::Fixed){
856         dpitch=(FXFont::Fixed!=pitch);
857         }
858       else if(wanthints&FXFont::Variable){
859         dpitch=(FXFont::Variable!=pitch);
860         }
861       else{
862         dpitch=0;
863         }
864 
865       // Scalable
866       if(wanthints&FXFont::Scalable){
867         dscalable=(FXFont::Scalable!=scalable);
868         }
869       else{
870         dscalable=0;
871         }
872 
873       // Rotatable
874       if(wanthints&FXFont::Rotatable){
875         drotatable=(FXFont::Rotatable!=rotatable);
876         }
877       else{
878         drotatable=0;
879         }
880 
881       // Polymorphic
882       if(wanthints&FXFont::Polymorphic){
883         dpolymorph=(FXFont::Polymorphic!=polymorph);
884         }
885       else{
886         dpolymorph=0;
887         }
888 
889       // If scalable, we can of course get the exact size we want
890       // We do not set dsize to 0, as we prefer a bitmapped font that gets within
891       // 10% over a scalable one that's exact, as the bitmapped fonts look much better
892       // at small sizes than scalable ones...
893       if(scalable){
894         dsize=wantsize/10;
895         size=wantsize;
896         }
897 
898       // We correct for the actual screen resolution; if the font is rendered at a
899       // 100 dpi, and we have a screen with 90dpi, the actual point size of the font
900       // should be multiplied by (100/90).
901       else{
902         size=(yres*points)/res;
903         dsize=Math::iabs(size-wantsize);
904         }
905 
906       FXTRACE((160,"%4d: dweight=%-3d dsize=%3d dslant=%d dsetwidth=%d dscalable=%d dpolymorph=%d xres=%-3d yres=%-3d xlfd=\"%s\"\n",f,dweight,dsize,dslant,dsetwidth,dscalable,dpolymorph,xres,yres,fontnames[f]));
907 
908       // But I'm NOT drinking any fucking Merlot!
909       if((dencoding<bencoding) || ((dencoding==bencoding) && ((drotatable<brotatable) || ((drotatable==brotatable) && ((dpitch<bpitch) || ((dpitch==bpitch) && ((dsize<bsize) || ((dsize==bsize) && ((dweight<bweight) || ((dweight==bweight) && ((dslant<bslant) || ((dslant==bslant) && ((dsetwidth<bsetwidth) || ((dsetwidth==bsetwidth) && ((dscalable<bscalable) || ((dscalable==bscalable) && (dpolymorph<bpolymorph))))))))))))))))){
910 
911         // Best match
912         actualName=field[1];
913         actualName.append(" [");
914         actualName.append(field[0]);
915         actualName.append("]");
916         actualSize=size;
917         actualWeight=weight;
918         actualSlant=slant;
919         actualSetwidth=setwidth;
920         actualEncoding=encoding;
921         flags=pitch|scalable|polymorph|rotatable;
922 
923         // Closeness
924         bencoding=dencoding;
925         brotatable=drotatable;
926         bpitch=dpitch;
927         bsize=dsize;
928         bweight=dweight;
929         bslant=dslant;
930         bsetwidth=dsetwidth;
931         bscalable=dscalable;
932         bpolymorph=dpolymorph;
933         bxres=xres;
934         byres=yres;
935         b=f;
936         }
937       }
938 
939     // Got a font?
940     if(0<=b){
941 
942       FXTRACE((150,"bweight=%-3d bsize=%3d bslant=%d bsetwidth=%d bscalable=%d bpolymorph=%d bxres=%-3d byres=%-3d xlfd=\"%s\"\n",bweight,bsize,bslant,bsetwidth,bscalable,bpolymorph,bxres,byres,fontnames[b]));
943 
944       // Keep desired font name
945       fxstrlcpy(xlfd,fontnames[b],sizeof(xlfd));
946 
947       // Free the list
948       XFreeFontNames(fontnames);
949 
950 /*
951       // If font is scaled or rotated, build custom xlfd
952       if(flags&(FXFont::Scalable|FXFont::Rotatable)){
953 
954         // Bust up XLFD into parts
955         fxstrlcpy(candidate,xlfd,sizeof(candidate));
956         xlfdSplit(field,candidate);
957 
958         // Create rotated font
959         if(flags&FXFont::Rotatable){
960           a=0.00027270769562411399179*angle;
961           c=(cos(a)*res*actualSize)/(10.0*byres);
962           s=(sin(a)*res*actualSize)/(10.0*byres);
963           __snprintf(xlfd,sizeof(xlfd),"-%s-%s-%s-%s-%s-%s-*-[%s%.3f %s%.3f %s%.3f %s%.3f]-%d-%d-%s-*-%s",field[0],field[1],field[2],field[3],field[4],field[5],SGN(c),fabs(c),SGN(s),fabs(s),SGN(-s),fabs(s),SGN(c),fabs(c),bxres,byres,field[10],field[12]);
964           }
965 
966         // Create scaled font
967         else{
968           __snprintf(xlfd,sizeof(xlfd),"-%s-%s-%s-%s-%s-%s-*-%d-%d-%d-%s-*-%s",field[0],field[1],field[2],field[3],field[4],field[5],(res*actualSize)/byres,bxres,byres,field[10],field[12]);
969           }
970         }
971 
972       // Try load it
973       font=XLoadQueryFont(DISPLAY(getApp()),xlfd);
974 */
975 
976       // If font is scaled or rotated, build custom xlfd
977       if(flags&(FXFont::Scalable|FXFont::Rotatable)){
978 
979         // Bust up XLFD into parts
980         fxstrlcpy(candidate,xlfd,sizeof(candidate));
981         xlfdSplit(field,candidate);
982 
983         // Create scaled font
984         __snprintf(xlfd,sizeof(xlfd),"-%s-%s-%s-%s-%s-%s-*-%d-%d-%d-%s-*-%s",field[0],field[1],field[2],field[3],field[4],field[5],(res*actualSize)/byres,bxres,byres,field[10],field[12]);
985 
986         FXTRACE((140,"XLoadQueryFont(\"%s\")\n",xlfd));
987 
988         // Load normal scaled font
989         fs=XLoadQueryFont(DISPLAY(getApp()),xlfd);
990 
991         // This is an ugly workaround:- according to docs, the X11 server is supposed to
992         // fill XCharStruct's in the XFontStruct such that the attribute data represents
993         // the escapement amount; however, this appears to be total garbage for all but a
994         // few of the installed fonts; moreover, the width member of the XCharStruct is
995         // also total garbage for these rotated fonts.
996         // The fix here is very tricky, but it works:- first, we grab the normal horizontal
997         // font's XFontStruct using XLoadQueryFont().  Then, we XUnloadFont() the font while
998         // keeping the XFontStruct.  Next, we load the rotated font using XLoadFont() and
999         // plug the font id into the XFontStruct.  This works, since while the XCharStruct's
1000         // may sometimes be located in read-only shared memory, the XFontStruct is always
1001         // allocated in the client by Xlib.
1002         if(fs && (flags&FXFont::Rotatable)){
1003           a=0.00027270769562411399179*angle;
1004           c=(Math::cos(a)*res*actualSize)/(10.0*byres);
1005           s=(Math::sin(a)*res*actualSize)/(10.0*byres);
1006           __snprintf(xlfd,sizeof(xlfd),"-%s-%s-%s-%s-%s-%s-*-[%s%.3f %s%.3f %s%.3f %s%.3f]-%d-%d-%s-*-%s",field[0],field[1],field[2],field[3],field[4],field[5],SGN(c),Math::fabs(c),SGN(s),Math::fabs(s),SGN(-s),Math::fabs(s),SGN(c),Math::fabs(c),bxres,byres,field[10],field[12]);
1007           XUnloadFont(DISPLAY(getApp()),((XFontStruct*)fs)->fid);
1008           ((XFontStruct*)fs)->fid=XLoadFont(DISPLAY(getApp()),xlfd);
1009           }
1010         }
1011 
1012       // Simple case for horizontally drawn fonts
1013       else{
1014 
1015         FXTRACE((140,"XLoadQueryFont(\"%s\")\n",xlfd));
1016 
1017         // Load normal scaled font
1018         fs=XLoadQueryFont(DISPLAY(getApp()),xlfd);
1019         }
1020 
1021 /*
1022       if(font){
1023         for(b=0; b<((XFontStruct*)font)->n_properties; b++){
1024           if(((XFontStruct*)font)->properties[b].name==XA_FONT){
1025             char *fn=XGetAtomName(DISPLAY(getApp()),((XFontStruct*)font)->properties[b].card32);
1026             fxstrlcpy(candidate,fn,sizeof(candidate));
1027             FXTRACE((100,"FONT = %s\n",candidate));
1028             xlfdSplit(field,candidate);
1029             XFree(fn);
1030             FXTRACE((100,"mat  = %s\n",field[6]));
1031             }
1032           else{
1033             FXTRACE((100,"%d (%s) = %d\n",((XFontStruct*)font)->properties[b].name,XGetAtomName(DISPLAY(getApp()),((XFontStruct*)font)->properties[b].name),((XFontStruct*)font)->properties[b].card32));
1034             }
1035           }
1036         }
1037 */
1038       return fs;
1039       }
1040     }
1041   return NULL;
1042   }
1043 
1044 
1045 #endif //////////////////////////////////////////////////////////////////////////
1046 
1047 
1048 /*******************************************************************************/
1049 
1050 // Object implementation
1051 FXIMPLEMENT(FXFont,FXId,NULL,0)
1052 
1053 
1054 // Deserialization
FXFont()1055 FXFont::FXFont(){
1056   wantedSize=0;
1057   actualSize=0;
1058   wantedWeight=0;
1059   actualWeight=0;
1060   wantedSlant=0;
1061   actualSlant=0;
1062   wantedSetwidth=0;
1063   actualSetwidth=0;
1064   wantedEncoding=0;
1065   actualEncoding=0;
1066   hints=0;
1067   flags=0;
1068   angle=0;
1069   font=NULL;
1070 #ifdef WIN32
1071   dc=NULL;
1072 #endif
1073   }
1074 
1075 
1076 // Construct font from given font description
FXFont(FXApp * a,const FXString & string)1077 FXFont::FXFont(FXApp* a,const FXString& string):FXId(a){
1078   FXTRACE((100,"FXFont::FXFont %p\n",this));
1079   wantedSize=0;
1080   actualSize=0;
1081   wantedWeight=0;
1082   actualWeight=0;
1083   wantedSlant=0;
1084   actualSlant=0;
1085   wantedSetwidth=0;
1086   actualSetwidth=0;
1087   wantedEncoding=0;
1088   actualEncoding=0;
1089   hints=0;
1090   flags=0;
1091   angle=0;
1092   font=NULL;
1093 #ifdef WIN32
1094   dc=NULL;
1095 #endif
1096   setFont(string);
1097   }
1098 
1099 
1100 // Construct a font with given family name, size in points, weight, slant, character set encoding, setwidth, and hints
FXFont(FXApp * a,const FXString & face,FXuint size,FXuint weight,FXuint slant,FXuint encoding,FXuint setwidth,FXuint h)1101 FXFont::FXFont(FXApp* a,const FXString& face,FXuint size,FXuint weight,FXuint slant,FXuint encoding,FXuint setwidth,FXuint h):FXId(a),wantedName(face){
1102   FXTRACE((100,"FXFont::FXFont %p\n",this));
1103   wantedSize=10*size;
1104   wantedWeight=weight;
1105   wantedSlant=slant;
1106   wantedSetwidth=setwidth;
1107   wantedEncoding=encoding;
1108   actualSize=0;
1109   actualWeight=0;
1110   actualSlant=0;
1111   actualSetwidth=0;
1112   actualEncoding=0;
1113   hints=(h&~FXFont::X11);          // System-independent method
1114   flags=0;
1115   angle=0;
1116   font=NULL;
1117 #ifdef WIN32
1118   dc=NULL;
1119 #endif
1120   }
1121 
1122 
1123 // Construct font from font description
FXFont(FXApp * a,const FXFontDesc & fontdesc)1124 FXFont::FXFont(FXApp* a,const FXFontDesc& fontdesc):FXId(a),wantedName(fontdesc.face){
1125   FXTRACE((100,"FXFont::FXFont %p\n",this));
1126   wantedSize=fontdesc.size;
1127   wantedWeight=fontdesc.weight;
1128   wantedSlant=fontdesc.slant;
1129   wantedSetwidth=fontdesc.setwidth;
1130   wantedEncoding=fontdesc.encoding;
1131   actualSize=0;
1132   actualWeight=0;
1133   actualSlant=0;
1134   actualSetwidth=0;
1135   actualEncoding=0;
1136   hints=fontdesc.flags;
1137   flags=0;
1138   angle=0;
1139   font=NULL;
1140 #ifdef WIN32
1141   dc=NULL;
1142 #endif
1143   }
1144 
1145 
1146 // Return family part of name
getFamily() const1147 FXString FXFont::getFamily() const {
1148   return wantedName.before('[').trimEnd();
1149   }
1150 
1151 
1152 // Return foundry part of name
getFoundry() const1153 FXString FXFont::getFoundry() const {
1154   return wantedName.section("[]",1);
1155   }
1156 
1157 
1158 /*******************************************************************************/
1159 
1160 
1161 // Create font
create()1162 void FXFont::create(){
1163   if(!xid){
1164     if(getApp()->isInitialized()){
1165       FXTRACE((100,"%s::create %p\n",getClassName(),this));
1166 
1167 #if defined(WIN32)              ///// WIN32 /////
1168 
1169       FXString family=getFamily();
1170 
1171       FXTRACE((150,"%s::create: win32 font\n",getClassName()));
1172 
1173       // Try to match with specified family and foundry
1174       if(!family.empty()){
1175         family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",family.text(),family.text());
1176         font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,100);
1177         }
1178 
1179       // Uh-oh, we failed
1180       if(!xid){ throw FXFontException("unable to create font"); }
1181 
1182 #elif defined(HAVE_XFT_H)       ///// XFT /////
1183 
1184       FXString family=getFamily();
1185       FXString foundry=getFoundry();
1186       FXint    res;
1187 
1188       // Override screen resolution via registry
1189       res=getApp()->reg().readUIntEntry("SETTINGS","screenres",100);
1190 
1191       FXTRACE((150,"%s::create: xft font\n",getClassName()));
1192 
1193       // Try to match with specified family and foundry
1194       if(!family.empty()){
1195         family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",family.text(),family.text());
1196         if(!foundry.empty()){
1197           foundry=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",foundry.text(),foundry.text());
1198           font=match(family,foundry,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1199           }
1200         if(!font){
1201           font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1202           }
1203         }
1204 
1205       // Uh-oh, we failed
1206       if(!xid){ throw FXFontException("unable to create font"); }
1207 
1208 #else                           ///// XLFD /////
1209 
1210       FXString family=getFamily();
1211       FXString foundry=getFoundry();
1212       FXint    res;
1213 
1214       // Override screen resolution via registry
1215       res=getApp()->reg().readUIntEntry("SETTINGS","screenres",100);
1216 
1217       FXTRACE((150,"%s::create: xlfd font\n",getClassName()));
1218 
1219       // X11 font specification
1220       if(hints&FXFont::X11){
1221 
1222         // Resolve font name
1223         actualName=xlfdFont(DISPLAY(getApp()),wantedName);
1224 
1225         // Try load the font
1226         font=XLoadQueryFont(DISPLAY(getApp()),actualName.text());
1227         }
1228 
1229       // Platform independent specification
1230       if(!font){
1231 
1232         // First we try to match with specified family and foundry
1233         if(!family.empty()){
1234           family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",family.text(),family.text());
1235           if(!foundry.empty()){
1236             foundry=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS",foundry.text(),foundry.text());
1237             font=match(family,foundry,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1238             }
1239           if(!font){
1240             font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1241             }
1242           }
1243 
1244         // Try based on hints
1245         if(!font){
1246 
1247           // Try swiss if we want swiss or indicated no preference
1248           if((hints&(FXFont::Swiss|FXFont::System)) || !(hints&(FXFont::Decorative|FXFont::Modern|FXFont::Roman|FXFont::Script|FXFont::Swiss|FXFont::System))){
1249             family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","helvetica","helvetica");
1250             font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1251             if(!font){
1252               family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","lucida","lucida");
1253               font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1254               }
1255             }
1256 
1257           // Try roman
1258           else if(hints&FXFont::Roman){
1259             family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","times","times");
1260             font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1261             if(!font){
1262               family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","charter","charter");
1263               font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1264               }
1265             }
1266 
1267           // Try modern
1268           else if(hints&FXFont::Modern){
1269             family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","courier","courier");
1270             font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1271             if(!font){
1272               family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","lucidatypewriter","lucidatypewriter");
1273               font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1274               }
1275             }
1276 
1277           // Try decorative
1278           else if(hints&FXFont::Decorative){
1279             family=getApp()->reg().readStringEntry("FONTSUBSTITUTIONS","gothic","gothic");
1280             font=match(family,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1281             }
1282 
1283           // Try anything
1284           if(!font){
1285             font=match(FXString::null,FXString::null,wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding,hints,res);
1286             }
1287           }
1288         }
1289 
1290       // If we still don't have a font yet, use fixed font
1291       if(!font){
1292 
1293         // Resolve font name
1294         actualName="fixed";
1295 
1296         // Try load the font
1297         font=XLoadQueryFont(DISPLAY(getApp()),actualName.text());
1298         }
1299 
1300       // Remember font id
1301       if(font){ xid=((XFontStruct*)font)->fid; }
1302 
1303       // Uh-oh, we failed
1304       if(!xid){ throw FXFontException("unable to create font"); }
1305 
1306 #endif
1307 
1308       // What was really matched
1309       FXTRACE((100,"wantedName=%s wantedSize=%d wantedWeight=%d wantedSlant=%d wantedSetwidth=%d wantedEncoding=%d\n",wantedName.text(),wantedSize,wantedWeight,wantedSlant,wantedSetwidth,wantedEncoding));
1310       FXTRACE((100,"actualName=%s actualSize=%d actualWeight=%d actualSlant=%d actualSetwidth=%d actualEncoding=%d\n",actualName.text(),actualSize,actualWeight,actualSlant,actualSetwidth,actualEncoding));
1311       }
1312     }
1313   }
1314 
1315 
1316 // Detach font
detach()1317 void FXFont::detach(){
1318   if(xid){
1319     FXTRACE((100,"%s::detach %p\n",getClassName(),this));
1320 
1321 #if defined(WIN32)              ///// WIN32 /////
1322 
1323     // Free font metrics
1324     freeElms(font);
1325 
1326 #elif defined(HAVE_XFT_H)       ///// XFT /////
1327 
1328     XftFontClose(DISPLAY(getApp()),(XftFont*)font);
1329 
1330 #else                           ///// XLFD /////
1331 
1332     XFreeFont(DISPLAY(getApp()),(XFontStruct*)font);
1333 
1334 #endif
1335 
1336     // Forget all about actual font
1337     actualName=FXString::null;
1338     actualSize=0;
1339     actualWeight=0;
1340     actualSlant=0;
1341     actualSetwidth=0;
1342     actualEncoding=0;
1343     font=NULL;
1344     xid=0;
1345     }
1346   }
1347 
1348 
1349 // Destroy font
destroy()1350 void FXFont::destroy(){
1351   if(xid){
1352     if(getApp()->isInitialized()){
1353       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
1354 
1355 #if defined(WIN32)              ///// WIN32 /////
1356 
1357       // Necessary to prevent resource leak
1358       SelectObject((HDC)dc,GetStockObject(SYSTEM_FONT));
1359 
1360       // Delete font
1361       DeleteObject((HFONT)xid);
1362 
1363       // Delete dummy DC
1364       DeleteDC((HDC)dc);
1365 
1366       // Free font metrics
1367       freeElms(font);
1368 
1369 #elif defined(HAVE_XFT_H)       ///// XFT /////
1370 
1371       // Free font
1372       XftFontClose(DISPLAY(getApp()),(XftFont*)font);
1373 
1374 #else                           ///// XLFD /////
1375 
1376       // Free font
1377       XFreeFont(DISPLAY(getApp()),(XFontStruct*)font);
1378 
1379 #endif
1380       }
1381 
1382     // Forget all about actual font
1383     actualName=FXString::null;
1384     actualSize=0;
1385     actualWeight=0;
1386     actualSlant=0;
1387     actualSetwidth=0;
1388     actualEncoding=0;
1389     font=NULL;
1390     xid=0;
1391     }
1392   }
1393 
1394 
1395 /*******************************************************************************/
1396 
1397 
1398 // Set to new angle, in degrees*64 relative to positive x axis
setAngle(FXint ang)1399 void FXFont::setAngle(FXint ang){
1400   if(xid){ fxerror("%s::setAngle: font has already been created.\n",getClassName()); }
1401   angle=(ang+34560)%23040-11520;
1402   if(angle!=ang){
1403     angle=ang;
1404     }
1405   }
1406 
1407 /*
1408 WINGDIAPI DWORD WINAPI GetGlyphIndices(
1409   HDC hdc,       // handle to DC
1410   LPCTSTR lpstr, // string to convert
1411   int c,         // number of characters in string
1412   LPWORD pgi,    // array of glyph indices
1413   DWORD fl       // glyph options
1414 );
1415 Parameters
1416 hdc
1417 [in] Handle to the device context.
1418 lpstr
1419 [in] Pointer to the string to be converted.
1420 c
1421 [in] Number of characters in pgi.
1422 pgi
1423 [out] Array of glyph indices corresponding to the characters in the string.
1424 fl
1425 [in] Specifies how glyphs should be handled if they are not supported. This parameter can be the following value. Value Meaning
1426 GGI_MARK_NONEXISTING_GLYPHS Marks unsupported glyphs with the hexadecimal value 0xffff.
1427 */
1428 
1429 // Does font have given character glyph?
hasChar(FXwchar ch) const1430 FXbool FXFont::hasChar(FXwchar ch) const {
1431   if(font){
1432 #if defined(WIN32)              ///// WIN32 /////
1433     // FIXME may want to use GetGlyphIndices()
1434     return ((TEXTMETRIC*)font)->tmFirstChar<=ch && ch<=((TEXTMETRIC*)font)->tmLastChar;
1435 #elif defined(HAVE_XFT_H)       ///// XFT /////
1436     return XftCharExists(DISPLAY(getApp()),(XftFont*)font,ch);
1437 #else                           ///// XLFD /////
1438     const XFontStruct *fs=(XFontStruct*)font;
1439     const XCharStruct *cm;
1440     FXuchar row=ch>>8;
1441     FXuchar col=ch&255;
1442     if(fs->min_char_or_byte2<=col && col<=fs->max_char_or_byte2 && fs->min_byte1<=row && row<=fs->max_byte1){
1443       if(!fs->per_char) return true;
1444       cm=fs->per_char+((row-fs->min_byte1)*(fs->max_char_or_byte2-fs->min_char_or_byte2+1))+(col-fs->min_char_or_byte2);
1445       if(cm->width || cm->ascent || cm->descent || cm->rbearing || cm->lbearing) return true;
1446       }
1447 #endif
1448     }
1449   return false;
1450   }
1451 
1452 
1453 // Get first character glyph in font
getMinChar() const1454 FXwchar FXFont::getMinChar() const {
1455   if(font){
1456 #if defined(WIN32)              ///// WIN32 /////
1457     return ((TEXTMETRIC*)font)->tmFirstChar;
1458 #elif defined(HAVE_XFT_H)       ///// XFT /////
1459     return 0;                                           // FIXME
1460 #else                           ///// XLFD /////
1461     return (((XFontStruct*)font)->min_byte1<<8)|((XFontStruct*)font)->min_char_or_byte2;
1462 #endif
1463     }
1464   return 0;
1465   }
1466 
1467 
1468 // Get last character glyph in font
getMaxChar() const1469 FXwchar FXFont::getMaxChar() const {
1470   if(font){
1471 #if defined(WIN32)              ///// WIN32 /////
1472     return ((TEXTMETRIC*)font)->tmLastChar;
1473 #elif defined(HAVE_XFT_H)       ///// XFT /////
1474     return 0x10ffff;                                    // FIXME
1475 #else                           ///// XLFD /////
1476     return (((XFontStruct*)font)->max_byte1<<8)|((XFontStruct*)font)->max_char_or_byte2;
1477 #endif
1478     }
1479   return 0;
1480   }
1481 
1482 
1483 // Get font leading [that is lead-ing as in Pb!]
getFontLeading() const1484 FXint FXFont::getFontLeading() const {
1485   if(font){
1486 #if defined(WIN32)              ///// WIN32 /////
1487     return ((TEXTMETRIC*)font)->tmExternalLeading;
1488 #elif defined(HAVE_XFT_H)       ///// XFT /////
1489     return 0;                                           // FIXME
1490 #else                           ///// XLFD /////
1491     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent-((XFontStruct*)font)->max_bounds.ascent-((XFontStruct*)font)->max_bounds.descent;
1492 #endif
1493     }
1494   return 0;
1495   }
1496 
1497 
1498 // Get font line spacing [height+leading]
getFontSpacing() const1499 FXint FXFont::getFontSpacing() const {
1500   if(font){
1501 #if defined(WIN32)              ///// WIN32 /////
1502     return ((TEXTMETRIC*)font)->tmHeight;               // Includes font point size plus internal leading
1503 #elif defined(HAVE_XFT_H)       ///// XFT /////
1504     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1505 #else                           ///// XLFD /////
1506     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent;
1507 #endif
1508     }
1509   return 1;
1510   }
1511 
1512 
1513 // Left bearing
leftBearing(FXwchar ch) const1514 FXint FXFont::leftBearing(FXwchar ch) const {
1515   if(font){
1516 #if defined(WIN32)              ///// WIN32 /////
1517     return 0;                                           // FIXME
1518 #elif defined(HAVE_XFT_H)       ///// XFT /////
1519     return 0;                                           // FIXME
1520 #else                           ///// XLFD /////
1521     const XFontStruct *fs=(XFontStruct*)font;
1522     if(fs->per_char){
1523       FXuchar row=ch>>8;
1524       FXuchar col=ch&255;
1525       if(fs->min_char_or_byte2<=col && col<=fs->max_char_or_byte2 && fs->min_byte1<=row && row<=fs->max_byte1){
1526         const XCharStruct *cm=fs->per_char+((row-fs->min_byte1)*(fs->max_char_or_byte2-fs->min_char_or_byte2+1))+(col-fs->min_char_or_byte2);
1527         if(cm->width || cm->ascent || cm->descent) return cm->lbearing;
1528         }
1529       return fs->per_char[((fs->default_char>>8)-fs->min_byte1)*(fs->max_char_or_byte2-fs->min_char_or_byte2+1)+((fs->default_char&255)-fs->min_char_or_byte2)].lbearing;
1530       }
1531     return fs->min_bounds.lbearing;
1532 #endif
1533     }
1534   return 0;
1535   }
1536 
1537 
1538 // Right bearing
rightBearing(FXwchar ch) const1539 FXint FXFont::rightBearing(FXwchar ch) const {
1540   if(font){
1541 #if defined(WIN32)              ///// WIN32 /////
1542     return 0;                                           // FIXME
1543 #elif defined(HAVE_XFT_H)       ///// XFT /////
1544     return 0;                                           // FIXME
1545 #else                           ///// XLFD /////
1546     const XFontStruct *fs=(XFontStruct*)font;
1547     if(fs->per_char){
1548       FXuchar row=ch>>8;
1549       FXuchar col=ch&255;
1550       if(fs->min_char_or_byte2<=col && col<=fs->max_char_or_byte2 && fs->min_byte1<=row && row<=fs->max_byte1){
1551         const XCharStruct *cm=fs->per_char+((row-fs->min_byte1)*(fs->max_char_or_byte2-fs->min_char_or_byte2+1))+(col-fs->min_char_or_byte2);
1552         if(cm->width || cm->ascent || cm->descent) return cm->rbearing;
1553         }
1554       return fs->per_char[((fs->default_char>>8)-fs->min_byte1)*(fs->max_char_or_byte2-fs->min_char_or_byte2+1)+((fs->default_char&255)-fs->min_char_or_byte2)].rbearing;
1555       }
1556     return fs->min_bounds.rbearing;
1557 #endif
1558     }
1559   return 0;
1560   }
1561 
1562 
1563 // Is it a mono space font
isFontMono() const1564 FXbool FXFont::isFontMono() const {
1565   if(font){
1566 #if defined(WIN32)              ///// WIN32 /////
1567     return !(((TEXTMETRIC*)font)->tmPitchAndFamily&TMPF_FIXED_PITCH);
1568 #elif defined(HAVE_XFT_H)       ///// XFT /////
1569     XGlyphInfo i_extents,m_extents;
1570     XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)"i",1,&i_extents); // FIXME better than before but no cigar yet
1571     XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)"M",1,&m_extents);
1572     return i_extents.xOff==m_extents.xOff;
1573 #else                           ///// XLFD /////
1574     return ((XFontStruct*)font)->min_bounds.width == ((XFontStruct*)font)->max_bounds.width;
1575 #endif
1576     }
1577   return true;
1578   }
1579 
1580 
1581 // Get font width
getFontWidth() const1582 FXint FXFont::getFontWidth() const {
1583   if(font){
1584 #if defined(WIN32)              ///// WIN32 /////
1585     return ((TEXTMETRIC*)font)->tmMaxCharWidth;
1586 #elif defined(HAVE_XFT_H)       ///// XFT /////
1587     return ((XftFont*)font)->max_advance_width;
1588 #else                           ///// XLFD /////
1589     return ((XFontStruct*)font)->max_bounds.width;
1590 #endif
1591     }
1592   return 1;
1593   }
1594 
1595 
1596 // Get font height
getFontHeight() const1597 FXint FXFont::getFontHeight() const {
1598   if(font){
1599 #if defined(WIN32)              ///// WIN32 /////
1600     return ((TEXTMETRIC*)font)->tmHeight;
1601 #elif defined(HAVE_XFT_H)       ///// XFT /////
1602     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1603 #else                           ///// XLFD /////
1604     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent;
1605 #endif
1606     }
1607   return 1;
1608   }
1609 
1610 
1611 // Get font ascent
getFontAscent() const1612 FXint FXFont::getFontAscent() const {
1613   if(font){
1614 #if defined(WIN32)              ///// WIN32 /////
1615     return ((TEXTMETRIC*)font)->tmAscent;
1616 #elif defined(HAVE_XFT_H)       ///// XFT /////
1617     return ((XftFont*)font)->ascent;
1618 #else                           ///// XLFD /////
1619     return ((XFontStruct*)font)->ascent;
1620 #endif
1621     }
1622   return 1;
1623   }
1624 
1625 
1626 // Get font descent
getFontDescent() const1627 FXint FXFont::getFontDescent() const {
1628   if(font){
1629 #if defined(WIN32)              ///// WIN32 /////
1630     return ((TEXTMETRIC*)font)->tmDescent;
1631 #elif defined(HAVE_XFT_H)       ///// XFT /////
1632     return ((XftFont*)font)->descent;
1633 #else                           ///// XLFD /////
1634     return ((XFontStruct*)font)->descent;
1635 #endif
1636     }
1637   return 0;
1638   }
1639 
1640 
1641 // Calculate width of single wide character in this font
getCharWidth(const FXwchar ch) const1642 FXint FXFont::getCharWidth(const FXwchar ch) const {
1643   if(font){
1644 #if defined(WIN32)              ///// WIN32 /////
1645     FXnchar sbuffer[2];
1646     SIZE size;
1647     sbuffer[0]=ch;
1648     if(0xFFFF<ch){                      // Deal with surrogate pair
1649       sbuffer[0]=(ch>>10)+LEAD_OFFSET;
1650       sbuffer[1]=(ch&0x3FF)+TAIL_OFFSET;
1651       GetTextExtentPoint32W((HDC)dc,sbuffer,2,&size);
1652       return size.cx;
1653       }
1654     GetTextExtentPoint32W((HDC)dc,sbuffer,1,&size);
1655     return size.cx;
1656 #elif defined(HAVE_XFT_H)       ///// XFT /////
1657     XGlyphInfo extents;
1658     XftTextExtents32(DISPLAY(getApp()),(XftFont*)font,(const FcChar32*)&ch,1,&extents);
1659     return extents.xOff;
1660 #else                           ///// XLFD /////
1661     const XFontStruct *fs=(XFontStruct*)font;
1662     FXint width,size;
1663     FXuchar r,c;
1664     if(fs->per_char){
1665       r=ch>>8;
1666       c=ch&255;
1667       size=(fs->max_char_or_byte2-fs->min_char_or_byte2+1);
1668       if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1669         width=fs->per_char[(r-fs->min_byte1)*size+(c-fs->min_char_or_byte2)].width;
1670         if(width) return width;
1671         }
1672       r=fs->default_char>>8;
1673       c=fs->default_char&255;
1674       if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1675         return fs->per_char[(r-fs->min_byte1)*size+(c-fs->min_char_or_byte2)].width;
1676         }
1677       }
1678     return fs->min_bounds.width;
1679 #endif
1680     }
1681   return 1;
1682   }
1683 
1684 
1685 // Text width
getTextWidth(const FXchar * string,FXuint length) const1686 FXint FXFont::getTextWidth(const FXchar *string,FXuint length) const {
1687   if(!string && length){ fxerror("%s::getTextWidth: NULL string argument\n",getClassName()); }
1688   if(font){
1689 #if defined(WIN32)              ///// WIN32 /////
1690     FXnchar sbuffer[4096];
1691     FXint count=utf2ncs(sbuffer,string,ARRAYNUMBER(sbuffer),length);
1692     SIZE size;
1693     GetTextExtentPoint32W((HDC)dc,sbuffer,count,&size);
1694     return size.cx;
1695 #elif defined(HAVE_XFT_H)       ///// XFT /////
1696     XGlyphInfo extents;
1697     // This returns rotated metrics; FOX likes to work with unrotated metrics, so if angle
1698     // is not 0, we calculate the unrotated baseline; note however that the calculation is
1699     // not 100% pixel exact when the angle is not a multiple of 90 degrees.
1700     XftTextExtentsUtf8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)string,length,&extents);
1701     if(angle){ return (FXint)(0.5+Math::sqrt((FXdouble)(extents.xOff*extents.xOff+extents.yOff*extents.yOff))); }
1702     return extents.xOff;
1703 #else                           ///// XLFD /////
1704     const XFontStruct *fs=(XFontStruct*)font;
1705     FXint defwidth=fs->min_bounds.width;
1706     FXint width=0,ww;
1707     FXuint p=0;
1708     FXuint s;
1709     FXuchar r;
1710     FXuchar c;
1711     FXwchar w;
1712     if(fs->per_char){
1713       r=fs->default_char>>8;
1714       c=fs->default_char&255;
1715       s=(fs->max_char_or_byte2-fs->min_char_or_byte2+1);
1716       if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1717         defwidth=fs->per_char[(r-fs->min_byte1)*s+(c-fs->min_char_or_byte2)].width;
1718         }
1719       while(p<length){
1720         w=wc(string+p);
1721         p+=wclen(string+p);
1722         r=w>>8;
1723         c=w&255;
1724         if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1725           if((ww=fs->per_char[(r-fs->min_byte1)*s+(c-fs->min_char_or_byte2)].width)!=0){
1726             width+=ww;
1727             continue;
1728             }
1729           }
1730         width+=defwidth;
1731         }
1732       }
1733     else{
1734       while(p<length){
1735         p+=wclen(string+p);
1736         width+=defwidth;
1737         }
1738       }
1739     return width;
1740 #endif
1741     }
1742   return length;
1743   }
1744 
1745 
1746 // Text width
getTextWidth(const FXString & string) const1747 FXint FXFont::getTextWidth(const FXString& string) const {
1748   return getTextWidth(string.text(),string.length());
1749   }
1750 
1751 
1752 // Text height
getTextHeight(const FXchar * string,FXuint length) const1753 FXint FXFont::getTextHeight(const FXchar *string,FXuint length) const {
1754   if(!string && length){ fxerror("%s::getTextHeight: NULL string argument\n",getClassName()); }
1755   if(font){
1756 #if defined(WIN32)              ///// WIN32 /////
1757 //    SIZE size;
1758 //    FXASSERT(dc!=NULL);
1759 //    GetTextExtentPoint32((HDC)dc,string,length,&size);
1760 //    return size.cy;
1761     return ((TEXTMETRIC*)font)->tmHeight;
1762 #elif defined(HAVE_XFT_H)       ///// XFT /////
1763 //    XGlyphInfo extents;
1764 //    XftTextExtents8(DISPLAY(getApp()),(XftFont*)font,(const FcChar8*)text,n,&extents);
1765 //    return extents.height; // TODO: Is this correct?
1766     // Patch from ivan.markov@wizcom.bg
1767     return ((XftFont*)font)->ascent+((XftFont*)font)->descent;
1768 #else                           ///// XLFD /////
1769 //    XCharStruct chst; int dir,asc,desc;
1770 //    XTextExtents((XFontStruct*)font,string,length,&dir,&asc,&desc,&chst);
1771 //    return asc+desc;
1772     return ((XFontStruct*)font)->ascent+((XFontStruct*)font)->descent;
1773 #endif
1774     }
1775   return 1;
1776   }
1777 
1778 
1779 // Text height
getTextHeight(const FXString & string) const1780 FXint FXFont::getTextHeight(const FXString& string) const {
1781   return getTextHeight(string.text(),string.length());
1782   }
1783 
1784 
1785 /*
1786 static FX88591Codec codec_8859_1;
1787 static FX88592Codec codec_8859_2;
1788 static FX88593Codec codec_8859_3;
1789 static FX88594Codec codec_8859_4;
1790 static FX88595Codec codec_8859_5;
1791 static FX88596Codec codec_8859_6;
1792 static FX88597Codec codec_8859_7;
1793 static FX88598Codec codec_8859_8;
1794 static FX88599Codec codec_8859_9;
1795 static FX885910Codec codec_8859_10;
1796 static FX885911Codec codec_8859_11;
1797 static FX885913Codec codec_8859_13;
1798 static FX885914Codec codec_8859_14;
1799 static FX885915Codec codec_8859_15;
1800 static FX885916Codec codec_8859_16;
1801 
1802   FXchar sbuffer[4096];
1803   switch(actualEncoding){
1804     case FONTENCODING_ISO_8859_1: count=codec_8859_1.utf2mb(sbuffer,4096,string,length); break;
1805     case FONTENCODING_ISO_8859_2: count=codec_8859_2.utf2mb(sbuffer,4096,string,length); break;
1806     case FONTENCODING_ISO_8859_3: count=codec_8859_3.utf2mb(sbuffer,4096,string,length); break;
1807     case FONTENCODING_ISO_8859_4: count=codec_8859_4.utf2mb(sbuffer,4096,string,length); break;
1808     case FONTENCODING_ISO_8859_5: count=codec_8859_5.utf2mb(sbuffer,4096,string,length); break;
1809     case FONTENCODING_ISO_8859_6: count=codec_8859_6.utf2mb(sbuffer,4096,string,length); break;
1810     case FONTENCODING_ISO_8859_7: count=codec_8859_7.utf2mb(sbuffer,4096,string,length); break;
1811     case FONTENCODING_ISO_8859_8: count=codec_8859_8.utf2mb(sbuffer,4096,string,length); break;
1812     case FONTENCODING_ISO_8859_9: count=codec_8859_9.utf2mb(sbuffer,4096,string,length); break;
1813     case FONTENCODING_ISO_8859_10: count=codec_8859_10.utf2mb(sbuffer,4096,string,length); break;
1814     case FONTENCODING_ISO_8859_11: count=codec_8859_11.utf2mb(sbuffer,4096,string,length); break;
1815     case FONTENCODING_ISO_8859_13: count=codec_8859_13.utf2mb(sbuffer,4096,string,length); break;
1816     case FONTENCODING_ISO_8859_14: count=codec_8859_14.utf2mb(sbuffer,4096,string,length); break;
1817     case FONTENCODING_ISO_8859_15: count=codec_8859_15.utf2mb(sbuffer,4096,string,length); break;
1818     case FONTENCODING_ISO_8859_16: count=codec_8859_16.utf2mb(sbuffer,4096,string,length); break;
1819     default: count=0; break;
1820     }
1821   XDrawString(DISPLAY(getApp()),((FXDCWindow*)dc)->surface->id(),(GC)((FXDCWindow*)dc)->ctx,x,y,sbuffer,count);
1822 */
1823 
1824 
1825 /*
1826   /// Draw text starting at x,y
1827   virtual void drawText(FXDC* dc,FXint x,FXint y,const FXString& string) const;
1828 
1829   /// Draw text starting at x,y
1830   virtual void drawText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const;
1831 
1832   /// Draw text starting at x,y over filled background
1833   virtual void drawImageText(FXDC* dc,FXint x,FXint y,const FXString& string) const;
1834 
1835   /// Draw text starting at x,y over filled background
1836   virtual void drawImageText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const;
1837 
1838 
1839 #if defined(WIN32)              ///// WIN32 /////
1840 
1841 // Draw text starting at x,y
1842 void FXFont::drawText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const {
1843   FXnchar sbuffer[4096];
1844   FXint iBkMode=SetBkMode((HDC)dc->ctx,TRANSPARENT);
1845   FXint count=utf2ncs(sbuffer,string,ARRAYNUMBER(sbuffer),FXMIN(length,4096));
1846   FXASSERT(count<=length);
1847   TextOutW((HDC)dc->ctx,x,y,sbuffer,count);
1848   SetBkMode((HDC)dc->ctx,iBkMode);
1849   }
1850 
1851 #elif defined(HAVE_XFT_H)       ///// XFT /////
1852 
1853 // Draw text starting at x,y
1854 void FXFont::drawText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const {
1855   XftColor color;
1856   color.pixel=((FXDCWindow*)dc)->devfg;
1857   color.color.red=FXREDVAL(((FXDCWindow*)dc)->fg)*257;
1858   color.color.green=FXGREENVAL(((FXDCWindow*)dc)->fg)*257;
1859   color.color.blue=FXBLUEVAL(((FXDCWindow*)dc)->fg)*257;
1860   color.color.alpha=FXALPHAVAL(((FXDCWindow*)dc)->fg)*257;
1861   XftDrawStringUtf8((XftDraw*)((FXDCWindow*)dc)->xftDraw,&color,(XftFont*)((FXDCWindow*)dc)->font->font,x,y,(const FcChar8*)string,length);
1862   }
1863 
1864 #else                           ///// XLFD /////
1865 
1866 static FXint utf2db(XChar2b *dst,const FXchar *src,FXint n){
1867   FXint len,p;
1868   FXwchar w;
1869   for(p=len=0; p<n; p+=wclen(src+p),len++){
1870     w=wc(src+p);
1871     dst[len].byte1=(w>>8);
1872     dst[len].byte2=(w&255);
1873     }
1874   return len;
1875   }
1876 
1877 
1878 // Draw text starting at x,y
1879 void FXFont::drawText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const {
1880   const XFontStruct *fs=(XFontStruct*)font;
1881   FXint count,escapement,defwidth,ww,size,i;
1882   FXdouble ang,ux,uy;
1883   FXuchar r,c;
1884   XChar2b sbuffer[4096];
1885   count=utf2db(sbuffer,string,FXMIN(length,4096));
1886   FXASSERT(count<=length);
1887   if(angle){
1888     ang=angle*0.00027270769562411399179;
1889     defwidth=fs->min_bounds.width;
1890     ux=cos(ang);
1891     uy=sin(ang);
1892     if(fs->per_char){
1893       r=fs->default_char>>8;
1894       c=fs->default_char&255;
1895       size=(fs->max_char_or_byte2-fs->min_char_or_byte2+1);
1896       if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1897         defwidth=fs->per_char[(r-fs->min_byte1)*size+(c-fs->min_char_or_byte2)].width;
1898         }
1899       for(i=escapement=0; i<count; i++){
1900         XDrawString16(DISPLAY(getApp()),((FXDCWindow*)dc)->surface->id(),(GC)((FXDCWindow*)dc)->ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
1901         r=sbuffer[i].byte1;
1902         c=sbuffer[i].byte2;
1903         escapement+=defwidth;
1904         if(fs->min_char_or_byte2<=c && c<=fs->max_char_or_byte2 && fs->min_byte1<=r && r<=fs->max_byte1){
1905           if((ww=fs->per_char[(r-fs->min_byte1)*size+(c-fs->min_char_or_byte2)].width)!=0) escapement+=ww-defwidth;
1906           }
1907         }
1908       }
1909     else{
1910       for(i=escapement=0; i<count; i++){
1911         XDrawString16(DISPLAY(getApp()),((FXDCWindow*)dc)->surface->id(),(GC)((FXDCWindow*)dc)->ctx,(FXint)(x+escapement*ux),(FXint)(y-escapement*uy),&sbuffer[i],1);
1912         escapement+=defwidth;
1913         }
1914       }
1915     }
1916   else{
1917     XDrawString16(DISPLAY(getApp()),((FXDCWindow*)dc)->surface->id(),(GC)((FXDCWindow*)dc)->ctx,x,y,sbuffer,count);
1918     }
1919   }
1920 
1921 
1922 #endif
1923 
1924 
1925 // Draw text starting at x,y
1926 void FXFont::drawText(FXDC* dc,FXint x,FXint y,const FXString& string) const {
1927   drawText(dc,x,y,string.text(),string.length());
1928   }
1929 
1930 
1931 
1932 // Draw text starting at x,y over filled background
1933 void FXFont::drawImageText(FXDC* dc,FXint x,FXint y,const FXchar* string,FXuint length) const {
1934   // ...
1935   }
1936 
1937 
1938 // Draw text starting at x,y over filled background
1939 void FXFont::drawImageText(FXDC* dc,FXint x,FXint y,const FXString& string) const {
1940   drawImageText(dc,x,y,string.text(),string.length());
1941   }
1942 */
1943 
1944 
1945 /*******************************************************************************/
1946 
1947 
1948 // Function to sort by name, weight, slant, and size
comparefont(const void * a,const void * b)1949 static int CDECL comparefont(const void *a,const void *b){
1950   const FXFontDesc *fa=(const FXFontDesc*)a;
1951   const FXFontDesc *fb=(const FXFontDesc*)b;
1952   FXint cmp=strcmp(fa->face,fb->face);
1953   return cmp ? cmp : (fa->weight!=fb->weight) ? fa->weight-fb->weight : (fa->slant!=fb->slant) ? fa->slant-fb->slant : fa->size-fb->size;
1954   }
1955 
1956 
1957 
1958 #if defined(WIN32)              ///////  MS-Windows ///////
1959 
1960 // Need to get some data into the callback function.
1961 struct FXFontStore {
1962   HDC         hdc;
1963   FXFontDesc *fonts;
1964   FXuint      numfonts;
1965   FXuint      size;
1966   FXFontDesc  desc;
1967   };
1968 
1969 
1970 // Callback function for EnumFontFamiliesEx()
EnumFontFamExProc(const LOGFONTA * lf,const TEXTMETRICA * lptm,DWORD FontType,LPARAM lParam)1971 static int CALLBACK EnumFontFamExProc(const LOGFONTA *lf,const TEXTMETRICA *lptm,DWORD FontType,LPARAM lParam){
1972   FXFontStore *pFontStore=(FXFontStore*)lParam;
1973   FXASSERT(lf);
1974   FXASSERT(lptm);
1975   FXASSERT(pFontStore);
1976 
1977   // Get pitch
1978   FXuint flags=0;
1979   if(lf->lfPitchAndFamily&FIXED_PITCH) flags|=FXFont::Fixed;
1980   if(lf->lfPitchAndFamily&VARIABLE_PITCH) flags|=FXFont::Variable;
1981 
1982   // Get hints
1983   if(lf->lfPitchAndFamily&FF_DONTCARE) flags|=0;
1984   if(lf->lfPitchAndFamily&FF_MODERN) flags|=FXFont::Modern;
1985   if(lf->lfPitchAndFamily&FF_ROMAN) flags|=FXFont::Roman;
1986   if(lf->lfPitchAndFamily&FF_SCRIPT) flags|=FXFont::Script;
1987   if(lf->lfPitchAndFamily&FF_DECORATIVE) flags|=FXFont::Decorative;
1988   if(lf->lfPitchAndFamily&FF_SWISS) flags|=FXFont::Swiss;
1989 
1990   // Skip if no match
1991   FXuint h=pFontStore->desc.flags;
1992   if((h&FXFont::Fixed) && !(flags&FXFont::Fixed)) return 1;
1993   if((h&FXFont::Variable) && !(flags&FXFont::Variable)) return 1;
1994 
1995   // Get weight (also guess from the name)
1996   FXuint weight=lf->lfWeight/10;
1997   if(strstr(lf->lfFaceName,"Bold")!=NULL) weight=FXFont::Bold;
1998   if(strstr(lf->lfFaceName,"Black")!=NULL) weight=FXFont::Black;
1999   if(strstr(lf->lfFaceName,"Demi")!=NULL) weight=FXFont::DemiBold;
2000   if(strstr(lf->lfFaceName,"Light")!=NULL) weight=FXFont::Light;
2001   if(strstr(lf->lfFaceName,"Medium")!=NULL) weight=FXFont::Medium;
2002 
2003   // Skip if weight doesn't match
2004   FXuint wt=pFontStore->desc.weight;
2005   if((wt!=0) && (wt!=weight)) return 1;
2006 
2007   // Get slant
2008   FXuint slant=FXFont::Straight;
2009   if(lf->lfItalic) slant=FXFont::Italic;
2010   if(strstr(lf->lfFaceName,"Italic")!=NULL) slant=FXFont::Italic;
2011   if(strstr(lf->lfFaceName,"Roman")!=NULL) slant=FXFont::Straight;
2012 
2013   // Skip if no match
2014   FXuint sl=pFontStore->desc.slant;
2015   if((sl!=0) && (sl!=slant)) return 1;
2016 
2017   // Get set width (also guess from the name)
2018   FXuint setwidth=0;
2019   if(strstr(lf->lfFaceName,"Cond")!=NULL) setwidth=FXFont::Condensed;
2020   if(strstr(lf->lfFaceName,"Narrow")!=NULL) setwidth=FXFont::Condensed;
2021   if(strstr(lf->lfFaceName,"Ext Cond")!=NULL) setwidth=FXFont::ExtraCondensed;
2022 
2023   // Skip if no match
2024   FXuint sw=pFontStore->desc.setwidth;
2025   if((sw!=0) && (sw!=setwidth)) return 1;
2026 
2027   // Get encoding
2028   FXuint encoding=CharSet2FXFontEncoding(lf->lfCharSet);
2029 
2030   // Skip if no match
2031   FXuint en=pFontStore->desc.encoding;
2032   if((en!=FONTENCODING_DEFAULT) && (en!=encoding)) return 1;
2033 
2034   // Is it scalable?
2035   if(FontType==TRUETYPE_FONTTYPE){
2036     flags|=FXFont::Scalable;
2037     }
2038 
2039   // Is it polymorphic?
2040   if(FontType==TRUETYPE_FONTTYPE){
2041     flags|=FXFont::Polymorphic;
2042     }
2043 
2044   // Initial allocation of storage?
2045   if(pFontStore->numfonts==0){
2046     allocElms(pFontStore->fonts,50);
2047     if(pFontStore->fonts==0) return 0;
2048     pFontStore->size=50;
2049     }
2050 
2051   // Grow the array if needed
2052   if(pFontStore->numfonts>=pFontStore->size){
2053     resizeElms(pFontStore->fonts,pFontStore->size+50);
2054     if(pFontStore->fonts==0) return 0;
2055     pFontStore->size+=50;
2056     }
2057 
2058   FXFontDesc *fonts=pFontStore->fonts;
2059   FXuint numfonts=pFontStore->numfonts;
2060 
2061   fxstrlcpy(fonts[numfonts].face,lf->lfFaceName,116);
2062   if(lf->lfHeight<0){
2063     fonts[numfonts].size=-MulDiv(lf->lfHeight,720,GetDeviceCaps(pFontStore->hdc,LOGPIXELSY));
2064     }
2065   else{
2066     fonts[numfonts].size=MulDiv(lf->lfHeight,720,GetDeviceCaps(pFontStore->hdc,LOGPIXELSY));
2067     }
2068   fonts[numfonts].weight=weight;
2069   fonts[numfonts].slant=slant;
2070   fonts[numfonts].encoding=encoding;
2071   fonts[numfonts].setwidth=setwidth;
2072   fonts[numfonts].flags=flags;
2073 
2074   pFontStore->fonts=fonts;
2075   pFontStore->numfonts++;
2076 
2077   // Must return 1 to continue enumerating fonts
2078   return 1;
2079   }
2080 
2081 
2082 // List all fonts matching hints
listFonts(FXFontDesc * & fonts,FXuint & numfonts,const FXString & face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h)2083 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
2084   FXuint i,j;
2085 
2086   // Initialize return values
2087   fonts=NULL;
2088   numfonts=0;
2089 
2090   // This data gets passed into the callback function
2091   FXFontStore fontStore;
2092   HDC hdc=GetDC(GetDesktopWindow());
2093   SaveDC(hdc);
2094   fontStore.hdc=hdc;
2095   fontStore.fonts=fonts;
2096   fontStore.numfonts=numfonts;
2097   fontStore.desc.weight=wt;
2098   fontStore.desc.slant=sl;
2099   fontStore.desc.setwidth=sw;
2100   fontStore.desc.encoding=en;
2101   fontStore.desc.flags=h;
2102 
2103   // Fill in the appropriate fields of the LOGFONT structure. Note that
2104   // EnumFontFamiliesEx() only examines the lfCharSet, lfFaceName and
2105   // lpPitchAndFamily fields of this struct.
2106   LOGFONTA lf;
2107   lf.lfHeight=0;
2108   lf.lfWidth=0;
2109   lf.lfEscapement=0;
2110   lf.lfOrientation=0;
2111   lf.lfWeight=0;
2112   lf.lfItalic=0;
2113   lf.lfUnderline=0;
2114   lf.lfStrikeOut=0;
2115   lf.lfCharSet=FXFontEncoding2CharSet(en);
2116   lf.lfOutPrecision=0;
2117   lf.lfClipPrecision=0;
2118   lf.lfQuality=0;
2119   lf.lfPitchAndFamily=0;                          // Should be MONO_FONT for Hebrew and Arabic?
2120   FXASSERT(face.length()<LF_FACESIZE);
2121   fxstrlcpy(lf.lfFaceName,face.text(),LF_FACESIZE);
2122 
2123   // Start enumerating!
2124   EnumFontFamiliesExA(hdc,&lf,EnumFontFamExProc,(LPARAM)&fontStore,0);
2125   RestoreDC(hdc,-1);
2126   ReleaseDC(GetDesktopWindow(),hdc);
2127 
2128   // Copy stuff back from the store
2129   fonts=fontStore.fonts;
2130   numfonts=fontStore.numfonts;
2131 
2132   // Any fonts found?
2133   if(numfonts==0){
2134     freeElms(fonts);
2135     return false;
2136     }
2137 
2138   // Sort them by name, weight, slant, and size respectively
2139   ::qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2140 
2141   // Weed out duplicates if we were just listing the face names
2142   if(lf.lfCharSet==DEFAULT_CHARSET && lf.lfFaceName[0]==0){
2143     i=j=1;
2144     while(j<numfonts){
2145       if(strcmp(fonts[i-1].face,fonts[j].face)!=0){
2146         fonts[i]=fonts[j];
2147         i++;
2148         }
2149       j++;
2150       }
2151     numfonts=i;
2152     }
2153 
2154   // Realloc to shrink the block
2155   resizeElms(fonts,numfonts);
2156 
2157 //   FXTRACE((150,"%d fonts:\n",numfonts));
2158 //   for(FXuint f=0; f<numfonts; f++){
2159 //     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));
2160 //     }
2161 //   FXTRACE((150,"\n\n"));
2162 
2163   return true;
2164   }
2165 
2166 
2167 #elif defined(HAVE_XFT_H)       ///////  X Freetype ///////
2168 
2169 
2170 // 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)2171 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
2172   int          encoding,setwidth,weight,slant,size,pitch,scalable,res,i,j;
2173   FXchar       fullname[256];
2174   FcPattern   *pattern,*p;
2175   FcObjectSet *objset;
2176   FcFontSet   *fontset;
2177   FcChar8     *fam,*fdy;
2178   FcBool       scale;
2179   FcCharSet   *charset;
2180   FXString     family;
2181   FXString     foundry;
2182   double       points;
2183 
2184   fonts=NULL;
2185   numfonts=0;
2186 
2187   // Need to have application
2188   if(!FXApp::instance()){ fxerror("FXFont::listFonts: no application object.\n"); }
2189 
2190   // Need to have display open
2191   if(!DISPLAY(FXApp::instance())){ fxerror("FXFont::listFonts: trying to list fonts before opening display.\n"); }
2192 
2193   // Get family part of name
2194   family=face.before('[').trimEnd();
2195 
2196   // Get foundry part of name
2197   foundry=face.section("[]",1);
2198 
2199   FXTRACE((150,"FXFont::listFonts: family=\"%s\" foundry=\"%s\" weight=%d slant=%d setwidth=%d encoding=%d hints=%x\n",family.text(),foundry.text(),wt,sl,sw,en,h));
2200 
2201   // Screen resolution may be overidden by registry
2202   res=FXApp::instance()->reg().readUIntEntry("SETTINGS","screenres",100);
2203 
2204   // Build object set
2205 #ifdef FC_WIDTH
2206   objset=FcObjectSetBuild(FC_FAMILY,FC_FOUNDRY,FC_SPACING,FC_SCALABLE,FC_WIDTH,FC_WEIGHT,FC_SLANT,FC_PIXEL_SIZE,NULL);
2207 #else
2208   objset=FcObjectSetBuild(FC_FAMILY,FC_FOUNDRY,FC_SPACING,FC_SCALABLE,FC_WEIGHT,FC_SLANT,FC_PIXEL_SIZE,NULL);
2209 #endif
2210   if(objset){
2211 
2212     // Create pattern object
2213     pattern=FcPatternCreate();
2214     if(pattern){
2215 
2216       // Set family
2217       if(!family.empty()){
2218         FcPatternAddString(pattern,FC_FAMILY,(const FcChar8*)family.text());
2219         }
2220 
2221       // Set foundry
2222       if(!foundry.empty()){
2223         FcPatternAddString(pattern,FC_FOUNDRY,(const FcChar8*)foundry.text());
2224         }
2225 
2226       // If we set this we get no fonts
2227 //      if(h&FXFont::Rotatable){
2228 //        const FcMatrix matrix={1.0,0.0,0.0,1.0};
2229 //        FcPatternAddMatrix(pattern,FC_MATRIX,&matrix);
2230 //        }
2231 
2232       // List fonts matching pattern
2233       fontset=FcFontList(0,pattern,objset);
2234       if(fontset && 0<fontset->nfont){
2235 
2236         // Allocate return array
2237         if(allocElms(fonts,fontset->nfont)){
2238 
2239           // Collect the info now...
2240           for(i=0; i<fontset->nfont; i++){
2241             p=fontset->fonts[i];
2242 
2243             // Get full face name
2244             fullname[0]=0;
2245             if(FcPatternGetString(p,FC_FAMILY,0,&fam)==FcResultMatch){
2246               fxstrlcpy(fullname,(const char*)fam,sizeof(fullname));
2247               if(FcPatternGetString(p,FC_FOUNDRY,0,&fdy)==FcResultMatch){
2248                 fxstrlcat(fullname," [",sizeof(fullname));
2249                 fxstrlcat(fullname,(const char*)fdy,sizeof(fullname));
2250                 fxstrlcat(fullname,"]",sizeof(fullname));
2251                 }
2252               }
2253 
2254 #ifdef FC_WIDTH
2255             // Get setwidth
2256             setwidth=0;
2257             if(FcPatternGetInteger(p,FC_WIDTH,0,&setwidth)==FcResultMatch){
2258               setwidth=fcSetWidth2SetWidth(setwidth);
2259               }
2260 #endif
2261 
2262             // Get weight
2263             weight=0;
2264             if(FcPatternGetInteger(p,FC_WEIGHT,0,&weight)==FcResultMatch){
2265               weight=fcWeight2Weight(weight);
2266               }
2267 
2268             // Get slant
2269             slant=0;
2270             if(FcPatternGetInteger(p,FC_SLANT,0,&slant)==FcResultMatch){
2271               slant=fcSlant2Slant(slant);
2272               }
2273 
2274             // Get pitch
2275             pitch=FXFont::Variable;
2276             if(FcPatternGetInteger(p,FC_SPACING,0,&pitch)==FcResultMatch){
2277 //              if(pitch==FC_MONO || pitch==FC_DUAL || pitch==FC_CHARCELL) pitch=FXFont::Fixed;
2278               if(pitch==FC_MONO || pitch==FC_CHARCELL) pitch=FXFont::Fixed;
2279               }
2280 
2281             // Pixel size works for both bitmap and scalable fonts
2282             size=0;
2283             if(FcPatternGetDouble(p,FC_PIXEL_SIZE,0,&points)==FcResultMatch){
2284               size=(int)((720.0*points)/res);
2285               }
2286 
2287             // Get scalable flag
2288             scalable=0;
2289             if(FcPatternGetBool(p,FC_SCALABLE,0,&scale)==FcResultMatch){
2290               if(scale) scalable=FXFont::Scalable;
2291               }
2292 
2293             // Get charset
2294             if(FcPatternGetCharSet(p,FC_CHARSET,0,&charset)==FcResultMatch){    // FIXME
2295               }
2296 
2297             // Get the encoding
2298             encoding=FONTENCODING_UNICODE;
2299 
2300             FXTRACE((160,"wt=%2d sl=%d sw=%3d en=%5d sz=%3d sc=%4x pi=%d name=%s\n",weight,slant,setwidth,encoding,size,scalable,pitch,fullname));
2301 
2302             // Skip if pitch does not match
2303             if((h&FXFont::Fixed) && (pitch!=FXFont::Fixed)) continue;
2304             if((h&FXFont::Variable) && (pitch!=FXFont::Variable)) continue;
2305 
2306             // Skip if weight does not match
2307             if((wt!=0) && (wt!=weight)) continue;
2308 
2309             // Skip if slant does not match
2310             if((sl!=0) && (sl!=slant)) continue;
2311 
2312             // Skip if setwidth does not match
2313             if((sw!=0) && (sw!=setwidth)) continue;
2314 
2315             // Want scalable
2316             if((h&FXFont::Scalable) && (scalable!=FXFont::Scalable)) continue;
2317 
2318             // If NULL face name, just list one of each face
2319             if(family.empty()){
2320               for(j=numfonts-1; j>=0; j--){
2321                 if(strcmp(fullname,fonts[j].face)==0) goto next;
2322                 }
2323               }
2324 
2325             // Add this font
2326             fxstrlcpy(fonts[numfonts].face,fullname,116);
2327             fonts[numfonts].size=size;
2328             fonts[numfonts].weight=weight;
2329             fonts[numfonts].slant=slant;
2330             fonts[numfonts].encoding=encoding;
2331             fonts[numfonts].setwidth=setwidth;
2332             fonts[numfonts].flags=pitch|scalable;
2333             numfonts++;
2334 
2335             // Next font
2336 next:       continue;
2337             }
2338 
2339           // Realloc to shrink the block
2340           resizeElms(fonts,numfonts);
2341 
2342           // Sort them by name, weight, slant, and size respectively
2343           ::qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2344           }
2345         FcFontSetDestroy(fontset);
2346         }
2347       FcPatternDestroy(pattern);
2348       }
2349     FcObjectSetDestroy(objset);
2350     }
2351   return (0<numfonts);
2352   }
2353 
2354 
2355 #else                           ///////  X XLFD ///////
2356 
2357 
2358 // Try find matching font
listFonts(FXFontDesc * & fonts,FXuint & numfonts,const FXString & face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h)2359 FXbool FXFont::listFonts(FXFontDesc*& fonts,FXuint& numfonts,const FXString& face,FXuint wt,FXuint sl,FXuint sw,FXuint en,FXuint h){
2360   FXuint   encoding,weight,slant,setwidth,pitch,scalable,rotatable,polymorph,xres,yres,points,size,res;
2361   FXchar   candidate[256],fullname[256];
2362   const FXchar  *field[13];
2363   FXchar **fontnames;
2364   FXint    nfontnames,f,j;
2365   FXString family;
2366   FXString foundry;
2367 
2368   fonts=NULL;
2369   numfonts=0;
2370 
2371   // Need to have application
2372   if(!FXApp::instance()){ fxerror("FXFont::listFonts: no application object.\n"); }
2373 
2374   // Need to have display open
2375   if(!DISPLAY(FXApp::instance())){ fxerror("FXFont::listFonts: trying to list fonts before opening display.\n"); }
2376 
2377   // Screen resolution may be overidden by registry
2378   res=FXApp::instance()->reg().readUIntEntry("SETTINGS","screenres",100);
2379 
2380   // Get family part of name
2381   family=face.before('[').trimEnd();
2382 
2383   // Get foundry part of name
2384   foundry=face.section("[]",1);
2385 
2386   FXTRACE((150,"FXFont::listFonts: family=\"%s\" foundry=\"%s\" weight=%d slant=%d setwidth=%d encoding=%d hints=%x\n",family.text(),foundry.text(),wt,sl,sw,en,h));
2387 
2388   // Match RAW X11
2389   if(h&FXFont::X11){
2390     __snprintf(candidate,sizeof(candidate),"%s",face.empty()?"*":face.text());
2391     }
2392 
2393   // Match XLFD
2394   else{
2395     __snprintf(candidate,sizeof(candidate),"-%s-%s-*-*-*-*-*-%s-*-*-*-*-*-*",foundry.empty() ? "*" : foundry.text(),family.empty() ? "*" : family.text(),(h&FXFont::Rotatable) ? "[1 0 0 1]" : "*");
2396     }
2397 
2398   // Get fonts matching the pattern
2399   fontnames=XListFonts(DISPLAY(FXApp::instance()),candidate,65535,&nfontnames);
2400   if(fontnames && 0<nfontnames){
2401 
2402     // Allocate return array
2403     if(!allocElms(fonts,nfontnames)){ XFreeFontNames(fontnames); return false; }
2404 
2405     // List them
2406     for(f=0; f<nfontnames; f++){
2407 
2408       // Break apart into fields
2409       fxstrlcpy(candidate,fontnames[f],sizeof(candidate));
2410       xlfdSplit(field,candidate);
2411 
2412       // Get info
2413       weight=xlfdWeight(field[2]);
2414       slant=xlfdSlant(field[3]);
2415       setwidth=xlfdSetwidth(field[4]);
2416       scalable=xlfdScalable(field[6],field[7],field[11]);
2417       polymorph=xlfdPolymorph(field[2],field[3],field[4],field[5]);
2418       rotatable=xlfdRotatable(field[6],field[7]);
2419       points=atoi(field[7]);
2420       xres=atoi(field[8]);
2421       yres=atoi(field[9]);
2422       pitch=xlfdPitch(field[10]);
2423       encoding=xlfdEncoding(field[12]);
2424 
2425       FXTRACE((160,"wt=%2d sl=%d sw=%3d en=%5d pt=%3d sc=%4x po=%4x ro=%4x xlfd=%s\n",weight,slant,setwidth,encoding,points,scalable,polymorph,rotatable,fontnames[f]));
2426 
2427       // The font can be rendered at any resolution
2428       if(xres==0 && yres==0){ xres=res; yres=res; }
2429 
2430       // Skip if encoding does not match
2431       if((en!=FONTENCODING_DEFAULT) && (en!=encoding)) continue;
2432 
2433       // Skip if pitch does not match
2434       if((h&FXFont::Fixed) && (pitch!=FXFont::Fixed)) continue;
2435       if((h&FXFont::Variable) && (pitch!=FXFont::Variable)) continue;
2436 
2437       // Skip if weight does not match
2438       if((wt!=0) && (wt!=weight)) continue;
2439 
2440       // Skip if slant does not match
2441       if((sl!=0) && (sl!=slant)) continue;
2442 
2443       // Skip if setwidth does not match
2444       if((sw!=0) && (sw!=setwidth)) continue;
2445 
2446       // Want rotatable
2447       if((h&FXFont::Rotatable) && (rotatable!=FXFont::Rotatable)) continue;
2448 
2449       // Want scalable
2450       if((h&FXFont::Scalable) && (scalable!=FXFont::Scalable)) continue;
2451 
2452       // If scalable, we can of course get the exact size we want
2453       if(scalable){
2454         size=0;
2455         }
2456 
2457       // Correct for the actual screen resolution
2458       else{
2459         size=(yres*points)/res;
2460         }
2461 
2462       // Get full face name
2463       fxstrlcpy(fullname,field[1],sizeof(fullname));
2464       if(field[0][0]){
2465         fxstrlcat(fullname," [",sizeof(fullname));
2466         fxstrlcat(fullname,field[0],sizeof(fullname));
2467         fxstrlcat(fullname,"]",sizeof(fullname));
2468         }
2469 
2470       // If NULL face name, just list one of each face
2471       if(family.empty()){
2472         for(j=numfonts-1; j>=0; j--){
2473           if(strcmp(fullname,fonts[j].face)==0) goto next;
2474           }
2475         }
2476 
2477       // Add this font
2478       fxstrlcpy(fonts[numfonts].face,fullname,116);
2479       fonts[numfonts].size=size;
2480       fonts[numfonts].weight=weight;
2481       fonts[numfonts].slant=slant;
2482       fonts[numfonts].encoding=encoding;
2483       fonts[numfonts].setwidth=setwidth;
2484       fonts[numfonts].flags=pitch|scalable|polymorph|rotatable;
2485       numfonts++;
2486 
2487       // Next font
2488 next: continue;
2489       }
2490 
2491     // Free the list
2492     XFreeFontNames(fontnames);
2493 
2494     // Realloc to shrink the block
2495     resizeElms(fonts,numfonts);
2496 
2497     // Sort them by name, weight, slant, and size respectively
2498     ::qsort(fonts,numfonts,sizeof(FXFontDesc),comparefont);
2499     }
2500   return (0<numfonts);
2501   }
2502 
2503 
2504 #endif
2505 
2506 
2507 /*******************************************************************************/
2508 
2509 
2510 // For tables
2511 struct ENTRY { const FXchar *name; FXuint value; };
2512 
2513 
2514 // Character set encodings
2515 static const ENTRY encodingtable[]={
2516   {"",FONTENCODING_DEFAULT},
2517   {"iso10646-1",FONTENCODING_UNICODE},
2518   {"iso8859-1",FONTENCODING_ISO_8859_1},
2519   {"iso8859-2",FONTENCODING_ISO_8859_2},
2520   {"iso8859-3",FONTENCODING_ISO_8859_3},
2521   {"iso8859-4",FONTENCODING_ISO_8859_4},
2522   {"iso8859-5",FONTENCODING_ISO_8859_5},
2523   {"iso8859-6",FONTENCODING_ISO_8859_6},
2524   {"iso8859-7",FONTENCODING_ISO_8859_7},
2525   {"iso8859-8",FONTENCODING_ISO_8859_8},
2526   {"iso8859-9",FONTENCODING_ISO_8859_9},
2527   {"iso8859-10",FONTENCODING_ISO_8859_10},
2528   {"iso8859-11",FONTENCODING_ISO_8859_11},
2529   {"iso8859-13",FONTENCODING_ISO_8859_13},
2530   {"iso8859-14",FONTENCODING_ISO_8859_14},
2531   {"iso8859-15",FONTENCODING_ISO_8859_15},
2532   {"iso8859-16",FONTENCODING_ISO_8859_16},
2533   {"koi8",FONTENCODING_KOI8},
2534   {"koi8-r",FONTENCODING_KOI8_R},
2535   {"koi8-u",FONTENCODING_KOI8_U},
2536   {"koi8-unified",FONTENCODING_KOI8_UNIFIED},
2537   {"cp437",FONTENCODING_CP437},
2538   {"cp850",FONTENCODING_CP850},
2539   {"cp851",FONTENCODING_CP851},
2540   {"cp852",FONTENCODING_CP852},
2541   {"cp855",FONTENCODING_CP855},
2542   {"cp856",FONTENCODING_CP856},
2543   {"cp857",FONTENCODING_CP857},
2544   {"cp860",FONTENCODING_CP860},
2545   {"cp861",FONTENCODING_CP861},
2546   {"cp862",FONTENCODING_CP862},
2547   {"cp863",FONTENCODING_CP863},
2548   {"cp864",FONTENCODING_CP864},
2549   {"cp865",FONTENCODING_CP865},
2550   {"cp866",FONTENCODING_CP866},
2551   {"cp869",FONTENCODING_CP869},
2552   {"cp870",FONTENCODING_CP870},
2553   {"cp1250",FONTENCODING_CP1250},
2554   {"cp1251",FONTENCODING_CP1251},
2555   {"cp1252",FONTENCODING_CP1252},
2556   {"cp1253",FONTENCODING_CP1253},
2557   {"cp1254",FONTENCODING_CP1254},
2558   {"cp1255",FONTENCODING_CP1255},
2559   {"cp1256",FONTENCODING_CP1256},
2560   {"cp1257",FONTENCODING_CP1257},
2561   {"cp1258",FONTENCODING_CP1258},
2562   {"cp874",FONTENCODING_CP874},
2563   {"ascii",FONTENCODING_ISO_8859_1}
2564   };
2565 
2566 
2567 // Font style table
2568 static const ENTRY styletable[]={
2569   {"",0},
2570   {"decorative",FXFont::Decorative},
2571   {"modern",FXFont::Modern},
2572   {"roman",FXFont::Roman},
2573   {"script",FXFont::Script},
2574   {"swiss",FXFont::Swiss},
2575   {"system",FXFont::System}
2576   };
2577 
2578 
2579 // Font pitch table
2580 static const ENTRY pitchtable[]={
2581   {"",0},
2582   {"mono",FXFont::Fixed},
2583   {"fixed",FXFont::Fixed},
2584   {"constant",FXFont::Fixed},
2585   {"variable",FXFont::Variable},
2586   {"proportional",FXFont::Variable},
2587   {"c",FXFont::Fixed},
2588   {"m",FXFont::Fixed},
2589   {"p",FXFont::Variable}
2590   };
2591 
2592 
2593 // Font text angles
2594 static const ENTRY slanttable[]={
2595   {"",0},
2596   {"regular",FXFont::Straight},
2597   {"italic",FXFont::Italic},
2598   {"oblique",FXFont::Oblique},
2599   {"normal",FXFont::Straight},
2600   {"reverse italic",FXFont::ReverseItalic},
2601   {"reverse oblique",FXFont::ReverseOblique},
2602   {"r",FXFont::Straight},
2603   {"n",FXFont::Straight},
2604   {"i",FXFont::Italic},
2605   {"o",FXFont::Oblique},
2606   {"ri",FXFont::ReverseItalic},
2607   {"ro",FXFont::ReverseOblique}
2608   };
2609 
2610 
2611 // Set width table
2612 static const ENTRY setwidthtable[]={
2613   {"",0},
2614   {"ultracondensed",FXFont::UltraCondensed},
2615   {"extracondensed",FXFont::ExtraCondensed},
2616   {"condensed",FXFont::Condensed},
2617   {"narrow",FXFont::Condensed},
2618   {"compressed",FXFont::Condensed},
2619   {"semicondensed",FXFont::SemiCondensed},
2620   {"medium",FXFont::NonExpanded},
2621   {"normal",FXFont::NonExpanded},
2622   {"regular",FXFont::NonExpanded},
2623   {"semiexpanded",FXFont::SemiExpanded},
2624   {"expanded",FXFont::Expanded},
2625   {"wide",FXFont::ExtraExpanded},
2626   {"extraexpanded",FXFont::ExtraExpanded},
2627   {"ultraexpanded",FXFont::UltraExpanded},
2628   {"n",FXFont::Condensed},
2629   {"r",FXFont::NonExpanded},
2630   {"c",FXFont::Condensed},
2631   {"w",FXFont::ExtraExpanded},
2632   {"m",FXFont::NonExpanded},
2633   {"x",FXFont::Expanded}
2634   };
2635 
2636 
2637 // Weight table
2638 static const ENTRY weighttable[]={
2639   {"",0},
2640   {"thin",FXFont::Thin},
2641   {"extralight",FXFont::ExtraLight},
2642   {"light",FXFont::Light},
2643   {"normal",FXFont::Normal},
2644   {"regular",FXFont::Normal},
2645   {"medium",FXFont::Medium},
2646   {"demibold",FXFont::DemiBold},
2647   {"bold",FXFont::Bold},
2648   {"extrabold",FXFont::ExtraBold},
2649   {"heavy",FXFont::Black},
2650   {"black",FXFont::Black},
2651   {"b",FXFont::Bold},
2652   {"l",FXFont::Light},
2653   {"n",FXFont::Normal},
2654   {"r",FXFont::Normal},
2655   {"m",FXFont::Medium},
2656   };
2657 
2658 
2659 // Search for value and return name
findbyvalue(const ENTRY * table,FXint n,FXuint value)2660 static FXString findbyvalue(const ENTRY* table,FXint n,FXuint value){
2661   for(int i=0; i<n; i++){ if(table[i].value==value) return table[i].name; }
2662   return FXString::value(value);
2663   }
2664 
2665 
2666 // Search for name and return value
findbyname(const ENTRY * table,FXint n,const FXString & name)2667 static FXuint findbyname(const ENTRY* table,FXint n,const FXString& name){
2668   for(int i=0; i<n; i++){ if(comparecase(table[i].name,name)==0) return table[i].value; }
2669   return name.toUInt();
2670   }
2671 
2672 
2673 // Get style from string
styleFromString(const FXString & str)2674 FXuint FXFont::styleFromString(const FXString& str){
2675   return str.toUInt();
2676   }
2677 
2678 
2679 // Get string from style
stringFromStyle(FXuint style)2680 FXString FXFont::stringFromStyle(FXuint style){
2681    return FXString::value(style);
2682   }
2683 
2684 
2685 // Get slant from string
slantFromString(const FXString & str)2686 FXuint FXFont::slantFromString(const FXString& str){
2687   return findbyname(slanttable,ARRAYNUMBER(slanttable),str);
2688   }
2689 
2690 
2691 // Get string from slant
stringFromSlant(FXuint slant)2692 FXString FXFont::stringFromSlant(FXuint slant){
2693   return findbyvalue(slanttable,ARRAYNUMBER(slanttable),slant);
2694   }
2695 
2696 
2697 // Get weight from string
weightFromString(const FXString & str)2698 FXuint FXFont::weightFromString(const FXString& str){
2699   return findbyname(weighttable,ARRAYNUMBER(weighttable),str);
2700   }
2701 
2702 
2703 // Get string from weight
stringFromWeight(FXuint weight)2704 FXString FXFont::stringFromWeight(FXuint weight){
2705   return findbyvalue(weighttable,ARRAYNUMBER(weighttable),weight);
2706   }
2707 
2708 
2709 // Get setwidth from string
setWidthFromString(const FXString & str)2710 FXuint FXFont::setWidthFromString(const FXString& str){
2711   return findbyname(setwidthtable,ARRAYNUMBER(setwidthtable),str);
2712   }
2713 
2714 
2715 // Get string from setwidth
stringFromSetWidth(FXuint setwidth)2716 FXString FXFont::stringFromSetWidth(FXuint setwidth){
2717   return findbyvalue(setwidthtable,ARRAYNUMBER(setwidthtable),setwidth);
2718   }
2719 
2720 
2721 // Get encoding from string
encodingFromString(const FXString & str)2722 FXuint FXFont::encodingFromString(const FXString& str){
2723   return findbyname(encodingtable,ARRAYNUMBER(encodingtable),str);
2724   }
2725 
2726 
2727 // Get string from encoding
stringFromEncoding(FXuint encoding)2728 FXString FXFont::stringFromEncoding(FXuint encoding){
2729   return findbyvalue(encodingtable,ARRAYNUMBER(encodingtable),encoding);
2730   }
2731 
2732 
2733 // Change font description
setFontDesc(const FXFontDesc & fontdesc)2734 void FXFont::setFontDesc(const FXFontDesc& fontdesc){
2735   wantedName=fontdesc.face;
2736   wantedSize=fontdesc.size;
2737   wantedWeight=fontdesc.weight;
2738   wantedSlant=fontdesc.slant;
2739   wantedSetwidth=fontdesc.setwidth;
2740   wantedEncoding=fontdesc.encoding;
2741   hints=fontdesc.flags;
2742   }
2743 
2744 
2745 // Get font description
getFontDesc() const2746 FXFontDesc FXFont::getFontDesc() const {
2747   FXFontDesc result;
2748   fxstrlcpy(result.face,wantedName.text(),sizeof(result.face));
2749   result.size=wantedSize;
2750   result.weight=wantedWeight;
2751   result.slant=wantedSlant;
2752   result.setwidth=wantedSetwidth;
2753   result.encoding=wantedEncoding;
2754   result.flags=hints;
2755   return result;
2756   }
2757 
2758 
2759 // Get actual font description
getActualFontDesc() const2760 FXFontDesc FXFont::getActualFontDesc() const {
2761   FXFontDesc result;
2762   fxstrlcpy(result.face,actualName.text(),sizeof(result.face));
2763   result.size=actualSize;
2764   result.weight=actualWeight;
2765   result.slant=actualSlant;
2766   result.setwidth=actualSetwidth;
2767   result.encoding=actualEncoding;
2768   result.flags=flags;
2769   return result;
2770   }
2771 
2772 /*******************************************************************************/
2773 
2774 #if 0
2775   /// Construct font description
2776   FXFontDesc(const FXString& fc,FXuint sz,FXuint wt,FXuint sl,FXuint enc,FXuint sw,FXuint h);
2777 
2778 // Construct font description
2779 FXFontDesc::FXFontDesc(const FXString& fc,FXuint sz,FXuint wt,FXuint sl,FXuint enc,FXuint sw,FXuint h){
2780   memcpy(face,fc.text(),sizeof(face)-1);    // FIXME yes, not liking this...
2781   size=10*sz;
2782   weight=wt;
2783   slant=sl;
2784   setwidth=sw;
2785   encoding=enc;
2786   flags=(h&~FXFont::X11);          // System-independent method
2787   }
2788 #endif
2789 
2790 
2791 // Set font description from a string
setFont(const FXString & string)2792 void FXFontDesc::setFont(const FXString& string){
2793   FXint len=string.find(',');
2794   memset(face,0,sizeof(face));
2795   if(0<=len){
2796     memcpy(face,string.text(),FXMIN(len,sizeof(face)-1));
2797     size=string.section(',',1).toUInt();
2798     weight=FXFont::weightFromString(string.section(',',2));
2799     slant=FXFont::slantFromString(string.section(',',3));
2800     setwidth=FXFont::setWidthFromString(string.section(',',4));
2801     encoding=FXFont::encodingFromString(string.section(',',5));
2802     flags=FXFont::styleFromString(string.section(',',6));
2803     }
2804   else{
2805     fxstrlcpy(face,string.text(),sizeof(face));
2806     size=0;
2807     weight=0;
2808     slant=0;
2809     setwidth=0;
2810     encoding=0;
2811     flags=FXFont::X11;
2812     }
2813   }
2814 
2815 
2816 // Get string of font description
getFont() const2817 FXString FXFontDesc::getFont() const {
2818   FXString string=face;
2819   if(!(flags&FXFont::X11)){
2820     string.append(',');
2821     string.append(FXString::value(size));
2822     if(weight || slant || setwidth || encoding || flags){
2823       string.append(',');
2824       string.append(FXFont::stringFromWeight(weight));
2825       if(slant || setwidth || encoding || flags){
2826         string.append(',');
2827         string.append(FXFont::stringFromSlant(slant));
2828         if(setwidth || encoding || flags){
2829           string.append(',');
2830           string.append(FXFont::stringFromSetWidth(setwidth));
2831           if(encoding || flags){
2832             string.append(',');
2833             string.append(FXFont::stringFromEncoding(encoding));
2834             if(flags){
2835               string.append(',');
2836               string.append(FXFont::stringFromStyle(flags));
2837               }
2838             }
2839           }
2840         }
2841       }
2842     }
2843   return string;
2844   }
2845 
2846 
2847 /*******************************************************************************/
2848 
2849 
2850 // Change font description from a string
setFont(const FXString & string)2851 void FXFont::setFont(const FXString& string){
2852   FXint len;
2853 
2854   // Raw X11 font is only the name
2855   wantedName=string;
2856   wantedSize=0;
2857   wantedWeight=0;
2858   wantedSlant=0;
2859   wantedSetwidth=0;
2860   wantedEncoding=0;
2861   hints=FXFont::X11;
2862 
2863   // Normal font description
2864   len=string.find(',');
2865   if(0<=len){
2866 
2867     // Name and foundry
2868     wantedName.trunc(len);
2869 
2870     // Point size
2871     wantedSize=string.section(',',1).toUInt();
2872 
2873     // Weight
2874     wantedWeight=weightFromString(string.section(',',2));
2875 
2876     // Slant
2877     wantedSlant=slantFromString(string.section(',',3));
2878 
2879     // Set width
2880     wantedSetwidth=setWidthFromString(string.section(',',4));
2881 
2882     // Encoding
2883     wantedEncoding=encodingFromString(string.section(',',5));
2884 
2885     // Flags
2886     hints=styleFromString(string.section(',',6));
2887     }
2888   }
2889 
2890 
2891 
2892 // Return the font description as a string; keep it as simple
2893 // as possible by dropping defaulted fields at the end.
getFont() const2894 FXString FXFont::getFont() const {
2895   FXString string=wantedName;
2896 
2897   // Raw X11 font is only the name
2898   if(!(hints&FXFont::X11)){
2899 
2900     // Append size
2901     string.append(',');
2902     string.append(FXString::value(wantedSize));
2903 
2904     // Weight and other stuff
2905     if(wantedWeight || wantedSlant || wantedSetwidth || wantedEncoding || hints){
2906 
2907       // Append weight
2908       string.append(',');
2909       string.append(stringFromWeight(wantedWeight));
2910 
2911       // Slant and other stuff
2912       if(wantedSlant || wantedSetwidth || wantedEncoding || hints){
2913 
2914         // Append slant
2915         string.append(',');
2916         string.append(stringFromSlant(wantedSlant));
2917 
2918         // Setwidth and other stuff
2919         if(wantedSetwidth || wantedEncoding || hints){
2920 
2921           // Append set width
2922           string.append(',');
2923           string.append(stringFromSetWidth(wantedSetwidth));
2924 
2925           // Encoding and other stuff
2926           if(wantedEncoding || hints){
2927 
2928             // Append encoding
2929             string.append(',');
2930             string.append(stringFromEncoding(wantedEncoding));
2931 
2932             // Hints
2933             if(hints){
2934 
2935               // Append hint flags
2936               string.append(',');
2937               string.append(stringFromStyle(hints));
2938               }
2939             }
2940           }
2941         }
2942       }
2943     }
2944   return string;
2945   }
2946 
2947 
2948 /*******************************************************************************/
2949 
2950 
2951 // Save font to stream
save(FXStream & store) const2952 void FXFont::save(FXStream& store) const {
2953   FXId::save(store);
2954   store << wantedName;
2955   store << wantedSize;
2956   store << wantedWeight;
2957   store << wantedSlant;
2958   store << wantedSetwidth;
2959   store << wantedEncoding;
2960   store << angle;
2961   store << hints;
2962   }
2963 
2964 
2965 // Load font from stream; create() should be called later
load(FXStream & store)2966 void FXFont::load(FXStream& store){
2967   FXId::load(store);
2968   store >> wantedName;
2969   store >> wantedSize;
2970   store >> wantedWeight;
2971   store >> wantedSlant;
2972   store >> wantedSetwidth;
2973   store >> wantedEncoding;
2974   store >> angle;
2975   store >> hints;
2976   }
2977 
2978 
2979 // Clean up
~FXFont()2980 FXFont::~FXFont(){
2981   FXTRACE((100,"FXFont::~FXFont %p\n",this));
2982   destroy();
2983   }
2984 
2985 }
2986