1 /************************************************************************/
2 /* */
3 /* Analysis and manipulation of font names. */
4 /* */
5 /************************************************************************/
6
7 # include "utilPsConfig.h"
8
9 # include <stdlib.h>
10 # include <string.h>
11
12 # include <appDebugon.h>
13
14 # include "psFontName.h"
15
16 /************************************************************************/
17 /* */
18 /* Derive a font weight from the string designation. */
19 /* */
20 /************************************************************************/
21
utilFontWeightFromString(int * pWeight,int * pStart,int * pLength,const char * name)22 int utilFontWeightFromString( int * pWeight,
23 int * pStart,
24 int * pLength,
25 const char * name )
26 {
27 const char * s= name;
28
29 while( s[0] == ' ' )
30 { s++; }
31
32 while( *s )
33 {
34 if ( ! strncmp( s, "Extra Light", 11 ) )
35 {
36 *pWeight= FONTweightEXTRALIGHT;
37 *pStart= s- name;
38 *pLength= 11;
39 return 1;
40 }
41
42 if ( ! strncmp( s, "Ultralight", 10 ) )
43 {
44 *pWeight= FONTweightEXTRALIGHT;
45 *pStart= s- name;
46 *pLength= 10;
47 return 1;
48 }
49
50 if ( ! strncmp( s, "Light", 5 ) )
51 {
52 *pWeight= FONTweightLIGHT;
53 *pStart= s- name;
54 *pLength= 5;
55 return 1;
56 }
57
58 if ( ! strncmp( s, "Book", 4 ) )
59 {
60 *pWeight= FONTweightBOOK;
61 *pStart= s- name;
62 *pLength= 4;
63 return 1;
64 }
65
66 if ( ! strncmp( s, "Regular", 7 ) )
67 {
68 *pWeight= FONTweightREGULAR;
69 *pStart= s- name;
70 *pLength= 7;
71 return 1;
72 }
73 if ( ! strncmp( s, "Normal", 6 ) )
74 {
75 *pWeight= FONTweightREGULAR;
76 *pStart= s- name;
77 *pLength= 6;
78 return 1;
79 }
80 if ( ! strncmp( s, "Medium", 6 ) )
81 {
82 *pWeight= FONTweightMEDIUM;
83 *pStart= s- name;
84 *pLength= 6;
85 return 1;
86 }
87 if ( ! strncmp( s, "Roman", 5 ) )
88 {
89 *pWeight= FONTweightMEDIUM;
90 *pStart= s- name;
91 *pLength= 5;
92 return 1;
93 }
94
95
96 if ( ! strncmp( s, "Semibold", 8 ) )
97 {
98 *pWeight= FONTweightSEMIBOLD;
99 *pStart= s- name;
100 *pLength= 8;
101 return 1;
102 }
103 if ( ! strncmp( s, "Demibold", 8 ) )
104 {
105 *pWeight= FONTweightSEMIBOLD;
106 *pStart= s- name;
107 *pLength= 8;
108 return 1;
109 }
110 if ( ! strncmp( s, "Demi", 4 ) )
111 {
112 *pWeight= FONTweightSEMIBOLD;
113 *pStart= s- name;
114 *pLength= 4;
115 return 1;
116 }
117
118 if ( ! strncmp( s, "Bold", 4 ) )
119 {
120 *pWeight= FONTweightBOLD;
121 *pStart= s- name;
122 *pLength= 4;
123 return 1;
124 }
125
126 if ( ! strncmp( s, "Extrabold", 9 ) )
127 {
128 *pWeight= FONTweightEXTRABOLD;
129 *pStart= s- name;
130 *pLength= 9;
131 return 1;
132 }
133
134 if ( ! strncmp( s, "Heavy", 5 ) )
135 {
136 *pWeight= FONTweightEXTRABOLD;
137 *pStart= s- name;
138 *pLength= 5;
139 return 1;
140 }
141
142 if ( ! strncmp( s, "Black", 5 ) )
143 {
144 *pWeight= FONTweightBLACK;
145 *pStart= s- name;
146 *pLength= 5;
147 return 1;
148 }
149
150 while( s[0] && s[0] != ' ' )
151 { s++; }
152 while( s[0] == ' ' )
153 { s++; }
154 }
155
156 return 0;
157 }
158
159
utilFontWidthFromString(int * pWidth,int * pStart,int * pLength,const char * name)160 int utilFontWidthFromString( int * pWidth,
161 int * pStart,
162 int * pLength,
163 const char * name )
164 {
165 const char * s= name;
166
167 while( s[0] == ' ' )
168 { s++; }
169
170 while( *s )
171 {
172 if ( ! strncmp( s, "Narrow", 6 ) &&
173 ( s[6] == '\0' || s[6] == ' ' ) )
174 {
175 *pWidth= FONTwidthCONDENSED;
176 *pStart= s- name;
177 *pLength= 6;
178 return 1;
179 }
180
181 if ( ! strncmp( s, "Extra Condensed", 15 ) &&
182 ( s[6] == '\0' || s[6] == ' ' ) )
183 {
184 *pWidth= FONTwidthEXTRACONDENSED;
185 *pStart= s- name;
186 *pLength= 15;
187 return 1;
188 }
189
190 if ( ! strncmp( s, "Condensed", 9 ) &&
191 ( s[9] == '\0' || s[9] == ' ' ) )
192 {
193 *pWidth= FONTwidthCONDENSED;
194 *pStart= s- name;
195 *pLength= 9;
196 return 1;
197 }
198 if ( ! strncmp( s, "Compressed", 9 ) &&
199 ( s[9] == '\0' || s[9] == ' ' ) )
200 {
201 *pWidth= FONTwidthCONDENSED;
202 *pStart= s- name;
203 *pLength= 9;
204 return 1;
205 }
206 if ( ! strncmp( s, "Compact", 9 ) &&
207 ( s[9] == '\0' || s[9] == ' ' ) )
208 {
209 *pWidth= FONTwidthCONDENSED;
210 *pStart= s- name;
211 *pLength= 9;
212 return 1;
213 }
214
215 if ( ! strncmp( s, "Extended", 8 ) &&
216 ( s[8] == '\0' || s[8] == ' ' ) )
217 {
218 *pWidth= FONTwidthEXPANDED;
219 *pStart= s- name;
220 *pLength= 8;
221 return 1;
222 }
223
224 while( s[0] && s[0] != ' ' )
225 { s++; }
226 while( s[0] == ' ' )
227 { s++; }
228 }
229
230 return 0;
231 }
232
psRemoveWidthFromName(char * target,int maxlen,int * pWidth,const char * name)233 int psRemoveWidthFromName( char * target,
234 int maxlen,
235 int * pWidth,
236 const char * name )
237 {
238 int rval= 0;
239 int width= FONTwidthNORMAL;
240 int widthStart= -1;
241 int widthLength= -1;
242
243 int len= strlen( name );
244
245 if ( len > maxlen )
246 { SDEB(name); return -1; }
247 strcpy( target, name );
248
249 if ( utilFontWidthFromString( &width,
250 &widthStart, &widthLength, target ) )
251 {
252 char * to= target+ widthStart;
253 int tail= len- widthStart- widthLength;
254
255 memmove( to, to+ widthLength, tail+ 1 );
256 len -= widthLength;
257
258 while( len > 0 && target[len-1] == ' ' )
259 { target[len-1]= '\0'; len--; }
260
261 rval= 1;
262 }
263
264 *pWidth= width;
265 return rval;
266 }
267
268 /************************************************************************/
269 /* */
270 /* Move the piece of the name that gives the width from the name of */
271 /* the face to that of the family. */
272 /* */
273 /* The purpose of this action is to reach a situation where the */
274 /* variants of a family vary in weight and in slant, not in width. */
275 /* In that way, we can use the RTF perspective, where a font family */
276 /* can be used with different weight, slant and size. */
277 /* */
278 /* 1) If a width appears in the full name..... */
279 /* 2) Append it to the family name. */
280 /* 3) If there is no width string yet, allocate one. */
281 /* 4) Move pieces fragments of the full name: We want the family name */
282 /* to be a prefix of the full name again. */
283 /* */
284 /************************************************************************/
285
psFontInfoMoveWidthToFamilyName(AfmFontInfo * afi)286 int psFontInfoMoveWidthToFamilyName( AfmFontInfo * afi )
287 {
288 int width= FONTwidthNORMAL;
289 int widthStart= -1;
290 int widthLength= 0;
291
292 int familyLength= strlen( afi->afiFamilyName );
293 int familyIsPrefix;
294 int hasWidth;
295 int familyHasWidth;
296
297 familyHasWidth= utilFontWidthFromString( &width, &widthStart, &widthLength,
298 afi->afiFamilyName );
299
300 familyIsPrefix= strncmp( afi->afiFullName,
301 afi->afiFamilyName, familyLength ) == 0;
302
303 if ( familyIsPrefix )
304 {
305 hasWidth= utilFontWidthFromString( &width, &widthStart, &widthLength,
306 afi->afiFullName+ familyLength );
307 if ( hasWidth )
308 { widthStart += familyLength; }
309 }
310 else{
311 hasWidth= utilFontWidthFromString( &width, &widthStart, &widthLength,
312 afi->afiFullName );
313 }
314
315 /* 1 */
316 if ( hasWidth )
317 {
318 int fullLength= strlen( afi->afiFullName );
319
320 # if 0
321 /* "DejaVu Sans/Serif Condensed" from FontConfig, MdD dec 2006 */
322 if ( width != afi->afiWidthInt )
323 { SLLDEB(afi->afiFullName,width,afi->afiWidthInt); }
324 # endif
325
326 /* 2 */
327 if ( ! familyHasWidth )
328 {
329 char * fresh;
330
331 fresh= (char *)realloc( afi->afiFamilyName,
332 familyLength+ 1+ widthLength+ 1 );
333 if ( ! fresh )
334 { XDEB(fresh); return -1; }
335 afi->afiFamilyName= fresh;
336
337 afi->afiFamilyName[familyLength]= ' ';
338 strncpy( afi->afiFamilyName+ familyLength+ 1,
339 afi->afiFullName+ widthStart, widthLength )[widthLength]= '\0';
340 }
341
342 /* 3 */
343 if ( ! afi->afiWidthStr )
344 {
345 afi->afiWidthStr= (char *)malloc( widthLength+ 1 );
346 if ( afi->afiWidthStr )
347 {
348 strncpy( afi->afiWidthStr, afi->afiFullName+ widthStart,
349 widthLength )[widthLength]= '\0';
350 }
351 }
352
353 /* 4 */
354 if ( familyIsPrefix )
355 {
356 char * full;
357 char * to;
358 char * from= afi->afiFullName+ familyLength;
359
360 while( widthStart > 0 && afi->afiFullName[widthStart- 1] == ' ' )
361 { widthStart--; widthLength++; }
362 while( afi->afiFullName[widthStart+ widthLength] == ' ' )
363 { widthLength++; }
364
365 full= (char *)malloc( fullLength+ 2+ 1 );
366 if ( ! full )
367 { XDEB(full); return -1; }
368 else{
369 strcpy( full, afi->afiFamilyName );
370 to= full+ strlen( full );
371
372 if ( from- afi->afiFullName < widthStart )
373 {
374 *(to++)= ' ';
375 while( *from == ' ' )
376 { from++; }
377
378 while( from- afi->afiFullName < widthStart )
379 { *(to++)= *(from++); }
380 }
381
382 from= afi->afiFullName+ widthStart+ widthLength;
383 if ( *from )
384 {
385 *(to++)= ' ';
386 while( *from )
387 { *(to++)= *(from++); }
388 }
389
390 *to= '\0';
391 }
392
393 free( afi->afiFullName );
394 afi->afiFullName= full;
395 }
396 }
397
398 return 0;
399 }
400
401 /************************************************************************/
402
403 typedef struct Int2Str
404 {
405 int isI;
406 const char * isS;
407 } Int2Str;
408
psInt2String(int i,const Int2Str * is,int n)409 static const char * psInt2String( int i, const Int2Str * is, int n )
410 {
411 int j;
412
413 for ( j= 1; j < n; j++ )
414 {
415 if ( i < ( is[j-1].isI+ is[j].isI )/ 2 )
416 { return is[j- 1].isS; }
417 }
418
419 return is[n-1].isS;
420 }
421
psWidthStr(int width)422 const char * psWidthStr( int width )
423 {
424 static const Int2Str ws[]=
425 {
426 { FONTwidthULTRACONDENSED, "Ultracondensed" },
427 { FONTwidthEXTRACONDENSED, "Extracondensed" },
428 { FONTwidthCONDENSED, "Condensed" },
429 { FONTwidthSEMICONDENSED, "Semicondensed" },
430 { FONTwidthNORMAL, "Normal" },
431 { FONTwidthSEMIEXPANDED, "Semiexpanded" },
432 { FONTwidthEXPANDED, "Expanded" },
433 { FONTwidthEXTRAEXPANDED, "Extraexpanded" },
434 { FONTwidthULTRAEXPANDED, "Ultraexpanded" },
435 };
436
437 return psInt2String( width, ws, sizeof(ws)/sizeof(Int2Str) );
438 }
439
psWeightStr(int weight)440 const char * psWeightStr( int weight )
441 {
442 static const Int2Str ws[]=
443 {
444 { FONTweightTHIN, "Thin" },
445 { FONTweightEXTRALIGHT, "Extralight" },
446 { FONTweightLIGHT, "Light" },
447 { FONTweightBOOK, "Book" },
448 { FONTweightREGULAR, "Regular" },
449 { FONTweightMEDIUM, "Medium" },
450 { FONTweightDEMIBOLD, "Demibold" },
451 { FONTweightBOLD, "Bold" },
452 { FONTweightEXTRABOLD, "Extrabold" },
453 { FONTweightBLACK, "Black" },
454 };
455
456 return psInt2String( weight, ws, sizeof(ws)/sizeof(Int2Str) );
457 }
458
459 /************************************************************************/
460 /* */
461 /* Try to make something of the X11 font weight field. */
462 /* */
463 /* As the content of the X11 field is not covered by a standard, we */
464 /* have to live with what font designers and font servers choose to */
465 /* report. */
466 /* */
467 /************************************************************************/
468
psFontGetWeight(unsigned char * pWeight,const char * weight)469 int psFontGetWeight( unsigned char * pWeight,
470 const char * weight )
471 {
472 if ( ! strcmp( weight, "extralight" ) )
473 { *pWeight= FONTweightEXTRALIGHT; return 0; }
474 if ( ! strcmp( weight, "ultralight" ) )
475 { *pWeight= FONTweightEXTRALIGHT; return 0; }
476 if ( ! strcmp( weight, "thin" ) )
477 { *pWeight= FONTweightEXTRALIGHT; return 0; }
478
479 if ( ! strcmp( weight, "light" ) )
480 { *pWeight= FONTweightLIGHT; return 0; }
481
482 if ( ! strcmp( weight, "demilight" ) )
483 { *pWeight= FONTweightBOOK; return 0; }
484 if ( ! strcmp( weight, "semilight" ) )
485 { *pWeight= FONTweightBOOK; return 0; }
486 if ( ! strcmp( weight, "book" ) )
487 { *pWeight= FONTweightBOOK; return 0; }
488
489 if ( ! strcmp( weight, "" ) )
490 { *pWeight= FONTweightMEDIUM; return 0; }
491 if ( ! strcmp( weight, "roman" ) )
492 { *pWeight= FONTweightMEDIUM; return 0; }
493 if ( ! strcmp( weight, "medium" ) )
494 { *pWeight= FONTweightMEDIUM; return 0; }
495 if ( ! strcmp( weight, "normal" ) )
496 { *pWeight= FONTweightMEDIUM; return 0; }
497 if ( ! strcmp( weight, "regular" ) )
498 { *pWeight= FONTweightMEDIUM; return 0; }
499
500 if ( ! strcmp( weight, "semi bold" ) )
501 { *pWeight= FONTweightSEMIBOLD; return 0; }
502 if ( ! strcmp( weight, "demi bold" ) )
503 { *pWeight= FONTweightSEMIBOLD; return 0; }
504 if ( ! strcmp( weight, "semibold" ) )
505 { *pWeight= FONTweightSEMIBOLD; return 0; }
506 if ( ! strcmp( weight, "demibold" ) )
507 { *pWeight= FONTweightSEMIBOLD; return 0; }
508 if ( ! strcmp( weight, "demi" ) )
509 { *pWeight= FONTweightSEMIBOLD; return 0; }
510
511 if ( ! strcmp( weight, "bold" ) )
512 { *pWeight= FONTweightBOLD; return 0; }
513 if ( ! strcmp( weight, "heavy" ) )
514 { *pWeight= FONTweightBOLD; return 0; }
515
516 if ( ! strcmp( weight, "ultrabold" ) )
517 { *pWeight= FONTweightEXTRABOLD; return 0; }
518 if ( ! strcmp( weight, "extrablack" ) )
519 { *pWeight= FONTweightEXTRABOLD; return 0; }
520 if ( ! strcmp( weight, "extrabold" ) )
521 { *pWeight= FONTweightEXTRABOLD; return 0; }
522 if ( ! strcmp( weight, "extra bold" ) )
523 { *pWeight= FONTweightEXTRABOLD; return 0; }
524
525 if ( ! strcmp( weight, "black" ) )
526 { *pWeight= FONTweightBLACK; return 0; }
527 if ( ! strcmp( weight, "ultrablack" ) )
528 { *pWeight= FONTweightBLACK; return 0; }
529
530 SDEB(weight); return -1;
531 }
532
533 /************************************************************************/
534 /* */
535 /* Try to make something of the X11 font width field. */
536 /* */
537 /* As the content of the X11 field is not covered by a standard, we */
538 /* have to live with what font designers and font servers choose to */
539 /* report. */
540 /* */
541 /************************************************************************/
542
psFontGetWidth(int * pWidth,const char * swdth)543 int psFontGetWidth( int * pWidth,
544 const char * swdth )
545 {
546 if ( ! strcmp( swdth, "narrow" ) )
547 { *pWidth= FONTwidthCONDENSED; return 0; }
548 if ( ! strcmp( swdth, "extra condensed" ) )
549 { *pWidth= FONTwidthEXTRACONDENSED; return 0; }
550
551 if ( ! strcmp( swdth, "condensed" ) )
552 { *pWidth= FONTwidthCONDENSED; return 0; }
553
554 if ( ! strcmp( swdth, "semi condensed" ) )
555 { *pWidth= FONTwidthSEMICONDENSED; return 0; }
556 if ( ! strcmp( swdth, "semicondensed" ) )
557 { *pWidth= FONTwidthSEMICONDENSED; return 0; }
558
559 if ( ! strcmp( swdth, "normal" ) )
560 { *pWidth= FONTwidthNORMAL; return 0; }
561
562 if ( ! strcmp( swdth, "semi extended" ) )
563 { *pWidth= FONTwidthSEMIEXPANDED; return 0; }
564 if ( ! strcmp( swdth, "semi expanded" ) )
565 { *pWidth= FONTwidthSEMIEXPANDED; return 0; }
566 if ( ! strcmp( swdth, "semiexpanded" ) )
567 { *pWidth= FONTwidthSEMIEXPANDED; return 0; }
568
569 if ( ! strcmp( swdth, "extended" ) )
570 { *pWidth= FONTwidthEXPANDED; return 0; }
571 if ( ! strcmp( swdth, "expanded" ) )
572 { *pWidth= FONTwidthEXPANDED; return 0; }
573
574 SDEB(swdth); return -1;
575 }
576
577