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