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