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