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