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