1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "bitmapchar.h"
31
32 #include "bvedit.h"
33 #include "cvundoes.h"
34 #include "dumpbdf.h"
35 #include "fontforgevw.h"
36 #include "fvfonts.h"
37 #include "splinefill.h"
38 #include "splinesaveafm.h"
39 #include "tottf.h"
40 #include "ustring.h"
41 #include "utype.h"
42
43 #include <math.h>
44 #include <string.h>
45
46 int use_freetype_to_rasterize_fv = 1;
47 char *BDFFoundry=NULL;
48
49 struct std_bdf_props StandardProps[] = {
50 { "FONT", prt_atom, true },
51 { "COMMENT", prt_string, false },
52 { "FOUNDRY", prt_string|prt_property, true },
53 { "FAMILY_NAME", prt_string|prt_property, true },
54 { "WEIGHT_NAME", prt_string|prt_property, true },
55 { "SLANT", prt_string|prt_property, true },
56 { "SETWIDTH_NAME", prt_string|prt_property, true },
57 { "ADD_STYLE_NAME", prt_string|prt_property, true },
58 { "PIXEL_SIZE", prt_int|prt_property, true },
59 { "POINT_SIZE", prt_int|prt_property, true },
60 { "RESOLUTION_X", prt_uint|prt_property, true },
61 { "RESOLUTION_Y", prt_uint|prt_property, true },
62 { "SPACING", prt_string|prt_property, true },
63 { "AVERAGE_WIDTH", prt_int|prt_property, true },
64 { "CHARSET_REGISTRY", prt_string|prt_property, true },
65 { "CHARSET_ENCODING", prt_string|prt_property, true },
66 { "FONTNAME_REGISTRY", prt_string|prt_property, true },
67 { "CHARSET_COLLECTIONS", prt_string|prt_property, true },
68 { "BITS_PER_PIXEL", prt_int|prt_property, true },
69 { "FONT_NAME", prt_string|prt_property, true },
70 { "FACE_NAME", prt_string|prt_property, true },
71 { "COPYRIGHT", prt_string|prt_property, true },
72 { "FONT_VERSION", prt_string|prt_property, true },
73 { "FONT_ASCENT", prt_int|prt_property, true },
74 { "FONT_DESCENT", prt_int|prt_property, true },
75 { "UNDERLINE_POSITION", prt_int|prt_property, true },
76 { "UNDERLINE_THICKNESS", prt_int|prt_property, true },
77 { "X_HEIGHT", prt_int|prt_property, true },
78 { "CAP_HEIGHT", prt_int|prt_property, true },
79 { "DEFAULT_CHAR", prt_uint|prt_property, true },
80 { "RAW_ASCENT", prt_int|prt_property, true },
81 { "RAW_DESCENT", prt_int|prt_property, true },
82 { "ITALIC_ANGLE", prt_int|prt_property, true },
83 { "NORM_SPACE", prt_int|prt_property, true },
84 { "QUAD_WIDTH", prt_int|prt_property, true }, /* Depreciated */
85 { "RESOLUTION", prt_uint|prt_property, true }, /* Depreciated */
86 { "RELATIVE_SETWIDTH", prt_uint|prt_property, true },
87 { "RELATIVE_WEIGHT", prt_uint|prt_property, true },
88 { "SUPERSCRIPT_X", prt_int|prt_property, true },
89 { "SUPERSCRIPT_Y", prt_int|prt_property, true },
90 { "SUPERSCRIPT_SIZE", prt_int|prt_property, true },
91 { "SUBSCRIPT_X", prt_int|prt_property, true },
92 { "SUBSCRIPT_Y", prt_int|prt_property, true },
93 { "SUBSCRIPT_SIZE", prt_int|prt_property, true },
94 { "FIGURE_WIDTH", prt_int|prt_property, true },
95 { "AVG_LOWERCASE_WIDTH", prt_int|prt_property, true },
96 { "AVG_UPPERCASE_WIDTH", prt_int|prt_property, true },
97 { "WEIGHT", prt_uint|prt_property, false },
98 { "DESTINATION", prt_uint|prt_property, false },
99 { "MIN_SPACE", prt_int|prt_property, false },
100 { "MAX_SPACE", prt_int|prt_property, false },
101 { "END_SPACE", prt_int|prt_property, false },
102 { "SMALL_CAP_SIZE", prt_int|prt_property, false },
103 { "STRIKEOUT_ASCENT", prt_int|prt_property, false },
104 { "STRIKEOUT_DESCENT", prt_int|prt_property, false },
105 { "NOTICE", prt_string|prt_property, false },
106 { "FONT_TYPE", prt_string|prt_property, false },
107 { "RASTERIZER_NAME", prt_string|prt_property, false },
108 { "RASTERIZER_VERSION", prt_string|prt_property, false },
109 { "AXIS_NAMES", prt_string|prt_property, false },
110 { "AXIS_LIMITS", prt_string|prt_property, false },
111 { "AXIS_TYPES", prt_string|prt_property, false },
112 STD_BDF_PROPS_EMPTY
113 };
114
IsUnsignedBDFKey(const char * key)115 int IsUnsignedBDFKey(const char *key) {
116 /* X says that some properties are signed and some are unsigned */
117 /* neither bdf nor pcf supports this, but David (of freetype) */
118 /* thought the sfnt BDF table should include it */
119 /* Since these are X11 atom names, case is significant */
120 int i;
121
122 for ( i=0; StandardProps[i].name!=NULL; ++i )
123 if ( strcmp(key,StandardProps[i].name)==0 )
124 return(( StandardProps[i].type&~prt_property)==prt_uint );
125
126 return( false );
127 }
128
BdfPropHasString(BDFFont * font,const char * key,const char * def)129 const char *BdfPropHasString(BDFFont *font,const char *key, const char *def ) {
130 int i;
131
132 for ( i=0; i<font->prop_cnt; ++i ) if ( strcmp(font->props[i].name,key)==0 ) {
133 switch ( font->props[i].type&~prt_property ) {
134 case prt_string:
135 if ( font->props[i].u.str!=NULL ) /* Can be NULL when creating & defaulting a prop */
136 return( font->props[i].u.str );
137 break;
138 case prt_atom:
139 if ( font->props[i].u.atom!=NULL ) /* Can be NULL when creating & defaulting a prop */
140 return( font->props[i].u.atom );
141 break;
142 default:
143 break;
144 }
145 }
146 return( def );
147 }
148
BdfPropHasInt(BDFFont * font,const char * key,int def)149 int BdfPropHasInt(BDFFont *font,const char *key, int def ) {
150 int i;
151
152 for ( i=0; i<font->prop_cnt; ++i ) if ( strcmp(font->props[i].name,key)==0 ) {
153 switch ( font->props[i].type&~prt_property ) {
154 case prt_int: case prt_uint:
155 return( font->props[i].u.val );
156 break;
157 default:
158 break;
159 }
160 }
161 return( def );
162 }
163
BDFPropAddString(BDFFont * bdf,const char * keyword,const char * value,char * match_key)164 static void BDFPropAddString(BDFFont *bdf,const char *keyword,const char *value,char *match_key) {
165 int i;
166
167 if ( match_key!=NULL && strcmp(keyword,match_key)!=0 )
168 return;
169
170 for ( i=0; i<bdf->prop_cnt; ++i )
171 if ( strcmp(keyword,bdf->props[i].name)==0 ) {
172 if ( (bdf->props[i].type&~prt_property)==prt_string ||
173 (bdf->props[i].type&~prt_property)==prt_atom )
174 free( bdf->props[i].u.str );
175 break;
176 }
177 if ( i==bdf->prop_cnt ) {
178 if ( i>=bdf->prop_max )
179 bdf->props = realloc(bdf->props,(bdf->prop_max+=10)*sizeof(BDFProperties));
180 ++bdf->prop_cnt;
181 bdf->props[i].name = copy(keyword);
182 }
183 if ( strcmp(keyword,"FONT")==0 )
184 bdf->props[i].type = prt_atom;
185 else if ( strcmp(keyword,"COMMENT")==0 )
186 bdf->props[i].type = prt_string;
187 else
188 bdf->props[i].type = prt_string | prt_property;
189 bdf->props[i].u.str = copy(value);
190 }
191
BDFPropAddInt(BDFFont * bdf,const char * keyword,int value,char * match_key)192 static void BDFPropAddInt(BDFFont *bdf,const char *keyword,int value,char *match_key) {
193 int i;
194
195 if ( match_key!=NULL && strcmp(keyword,match_key)!=0 )
196 return;
197
198 for ( i=0; i<bdf->prop_cnt; ++i )
199 if ( strcmp(keyword,bdf->props[i].name)==0 ) {
200 if ( (bdf->props[i].type&~prt_property)==prt_string ||
201 (bdf->props[i].type&~prt_property)==prt_atom )
202 free( bdf->props[i].u.str );
203 break;
204 }
205 if ( i==bdf->prop_cnt ) {
206 if ( i>=bdf->prop_max )
207 bdf->props = realloc(bdf->props,(bdf->prop_max+=10)*sizeof(BDFProperties));
208 ++bdf->prop_cnt;
209 bdf->props[i].name = copy(keyword);
210 }
211 if ( IsUnsignedBDFKey(keyword) )
212 bdf->props[i].type = prt_uint | prt_property;
213 else
214 bdf->props[i].type = prt_int | prt_property;
215 bdf->props[i].u.val = value;
216 }
217
AllSame(BDFFont * font,int * avg,int * cnt)218 static const char *AllSame(BDFFont *font,int *avg,int *cnt) {
219 int c=0, a=0, common= -1;
220 int i;
221 BDFChar *bdfc;
222 int cell = -1;
223
224 /* Return 'P' if a proporitional font */
225 /* Return 'C' if an X11 "cell" font (all glyphs within (0,width)x(ascent,desent) & monospace ) */
226 /* Return 'M' if monospace (and not a cell) */
227 for ( i=0; i<font->glyphcnt; ++i ) {
228 if ( (bdfc = font->glyphs[i])!=NULL && !IsntBDFChar(bdfc)) {
229 ++c;
230 a += bdfc->width;
231 if ( common==-1 ) common = bdfc->width; else if ( common!=bdfc->width ) { common = -2; cell = 0; }
232 if ( cell ) {
233 if ( bdfc->xmin<0 || bdfc->xmax>common || bdfc->ymax>font->ascent ||
234 -bdfc->ymin>font->descent )
235 cell = 0;
236 else
237 cell = 1;
238 }
239 }
240 }
241 if ( c==0 ) *avg=0; else *avg = (10*a)/c;
242 *cnt = c;
243 return(common==-2 ? "P" : cell ? "C" : "M" );
244 }
245
BDFPropAppendString(BDFFont * bdf,const char * keyword,char * value)246 static void BDFPropAppendString(BDFFont *bdf,const char *keyword,char *value) {
247 int i = bdf->prop_cnt;
248
249 if ( i>=bdf->prop_max )
250 bdf->props = realloc(bdf->props,(bdf->prop_max+=10)*sizeof(BDFProperties));
251 ++bdf->prop_cnt;
252 bdf->props[i].name = copy(keyword);
253 if ( strcmp(keyword,"COMMENT")==0 )
254 bdf->props[i].type = prt_string;
255 else if ( strcmp(keyword,"FONT")==0 )
256 bdf->props[i].type = prt_atom;
257 else
258 bdf->props[i].type = prt_string | prt_property;
259 bdf->props[i].u.str = copy(value);
260 }
261
BDFPropReplace(BDFFont * bdf,const char * key,const char * value)262 static int BDFPropReplace(BDFFont *bdf,const char *key, const char *value) {
263 int i;
264 char *pt;
265
266 for ( i=0; i<bdf->prop_cnt; ++i ) if ( strcmp(bdf->props[i].name,key)==0 ) {
267 switch ( bdf->props[i].type&~prt_property ) {
268 case prt_string:
269 case prt_atom:
270 free( bdf->props[i].u.atom );
271 break;
272 default:
273 break;
274 }
275 if ( (bdf->props[i].type&~prt_property)!=prt_atom )
276 bdf->props[i].type = (bdf->props[i].type&prt_property)|prt_string;
277 pt = strchr(value,'\n');
278 if ( pt==NULL )
279 bdf->props[i].u.str = copy(value);
280 else
281 bdf->props[i].u.str = copyn(value,pt-value);
282 return( true );
283 }
284 return( false );
285 }
286
def_Charset_Col(SplineFont * sf,EncMap * map,char * buffer)287 static void def_Charset_Col(SplineFont *sf,EncMap *map, char *buffer) {
288 uint32 codepages[2];
289 /* A buffer with 250 bytes should be more than big enough */
290
291 OS2FigureCodePages(sf,codepages);
292 buffer[0] = '\0';
293 if ( codepages[1]&(1U<<31) )
294 strcat(buffer , "ASCII " );
295 if ( (codepages[1]&(1U<<30)) )
296 strcat(buffer , "ISOLatin1Encoding " );
297 if ( (codepages[0]&2) )
298 strcat(buffer , "ISO8859-2 " );
299 if ( (codepages[0]&4) )
300 strcat(buffer , "ISO8859-5 " );
301 if ( (codepages[0]&8) )
302 strcat(buffer , "ISO8859-7 " );
303 if ( (codepages[0]&0x10) )
304 strcat(buffer , "ISO8859-9 " );
305 if ( (codepages[0]&0x20) )
306 strcat(buffer , "ISO8859-8 " );
307 if ( (codepages[0]&0x40) )
308 strcat(buffer , "ISO8859-6 " );
309 if ( (codepages[0]&0x80) )
310 strcat(buffer , "ISO8859-4 " );
311 if ( (codepages[0]&0x10000) )
312 strcat(buffer , "ISO8859-11 " );
313 if ( (codepages[0]&0x20000) && (map->enc->is_unicodebmp || map->enc->is_unicodefull ))
314 strcat(buffer , "JISX0208.1997 " );
315 if ( (codepages[0]&0x40000) && (map->enc->is_unicodebmp || map->enc->is_unicodefull ) )
316 strcat(buffer , "GB2312.1980 " );
317 if ( (codepages[0]&0x80000) && (map->enc->is_unicodebmp || map->enc->is_unicodefull ))
318 strcat(buffer , "KSC5601.1992 " );
319 if ( (codepages[0]&0x100000) && (map->enc->is_unicodebmp || map->enc->is_unicodefull ))
320 strcat(buffer , "BIG5 " );
321 if ( (codepages[0]&0x80000000) )
322 strcat(buffer , "Symbol " );
323
324 strcat(buffer , EncodingName(map->enc) );
325 }
326
SFReplaceEncodingBDFProps(SplineFont * sf,EncMap * map)327 void SFReplaceEncodingBDFProps(SplineFont *sf,EncMap *map) {
328 BDFFont *bdf;
329 char buffer[250];
330 char reg[100], enc[40], *pt;
331 const char *bpt;
332
333 def_Charset_Col(sf,map, buffer);
334 def_Charset_Enc(map,reg,enc);
335
336 for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
337 BDFPropReplace(bdf,"CHARSET_REGISTRY", reg);
338 BDFPropReplace(bdf,"CHARSET_ENCODING", enc);
339 BDFPropReplace(bdf,"CHARSET_COLLECTIONS",buffer);
340 if ( (bpt = BdfPropHasString(bdf,"FONT", NULL))!=NULL ) {
341 strncpy(buffer,bpt,sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0';
342 pt = strrchr(buffer,'-');
343 if ( pt!=NULL ) for ( --pt; pt>buffer && *pt!='-'; --pt );
344 if ( pt>buffer ) {
345 sprintf( pt+1, "%s-%s", reg, enc);
346 BDFPropReplace(bdf,"FONT",buffer);
347 }
348 }
349 }
350 }
351
SFReplaceFontnameBDFProps(SplineFont * sf)352 void SFReplaceFontnameBDFProps(SplineFont *sf) {
353 BDFFont *bdf;
354 char *bpt, *pt;
355 char buffer2[300];
356
357 for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
358 BDFPropReplace(bdf,"FONT_NAME", sf->fontname);
359 BDFPropReplace(bdf,"FAMILY_NAME", sf->familyname);
360 BDFPropReplace(bdf,"FULL_NAME", sf->fullname);
361 BDFPropReplace(bdf,"COPYRIGHT", sf->copyright);
362 if ( (bpt = copy(BdfPropHasString(bdf,"FONT", NULL)))!=NULL ) {
363 if ( bpt[0]=='-' ) {
364 for ( pt = bpt+1; *pt && *pt!='-'; ++pt );
365 if ( *pt=='-' ) {
366 *pt = '\0';
367 strcpy(buffer2,bpt);
368 strcat(buffer2,"-");
369 strcat(buffer2,sf->familyname);
370 for ( ++pt ; *pt && *pt!='-'; ++pt );
371 strcat(buffer2,pt);
372 BDFPropReplace(bdf,"FONT",buffer2);
373 }
374 }
375 free(bpt);
376 }
377 }
378 }
379
BdfPropsCopy(BDFProperties * props,int cnt)380 BDFProperties *BdfPropsCopy(BDFProperties *props, int cnt ) {
381 BDFProperties *ret;
382 int i;
383
384 if ( cnt==0 )
385 return( NULL );
386 ret = malloc(cnt*sizeof(BDFProperties));
387 memcpy(ret,props,cnt*sizeof(BDFProperties));
388 for ( i=0; i<cnt; ++i ) {
389 ret[i].name = copy(ret[i].name);
390 if ( (ret[i].type&~prt_property)==prt_string || (ret[i].type&~prt_property)==prt_atom )
391 ret[i].u.str = copy(ret[i].u.str);
392 }
393 return( ret );
394 }
395
def_Charset_Enc(EncMap * map,char * reg,char * enc)396 void def_Charset_Enc(EncMap *map,char *reg,char *enc) {
397 char *pt;
398
399 if ( map->enc->is_custom || map->enc->is_original ) {
400 strcpy( reg, "FontSpecific" );
401 strcpy( enc, "0");
402 } else if ( (pt = strstr(map->enc->enc_name,"8859"))!=NULL ) {
403 strcpy( reg, "ISO8859" );
404 pt += 4;
405 if ( !isdigit(*pt)) ++pt;
406 strcpy(enc, pt );
407 } else if ( map->enc->is_unicodebmp || map->enc->is_unicodefull ) {
408 strcpy( reg, "ISO10646" );
409 strcpy( enc, "1" );
410 } else if ( strstr(map->enc->enc_name, "5601")!=NULL ) {
411 strcpy( reg, "KSC5601.1992" );
412 strcpy( enc, "3" );
413 } else if ( strstr(map->enc->enc_name, "2312")!=NULL ) {
414 strcpy( reg, "GB2312.1980" );
415 strcpy( enc, "0" );
416 } else if ( strstrmatch(map->enc->enc_name, "JISX0208")!=NULL ) {
417 strcpy( reg, "JISX0208.1997" );
418 strcpy( enc, "0" );
419 } else {
420 strcpy( reg, EncodingName(map->enc) );
421 pt = strchr( reg,'-');
422 if ( pt==NULL )
423 strcpy( enc, "0" );
424 else {
425 strcpy( enc, pt+1 );
426 *pt = '\0';
427 }
428 }
429 }
430
decomposename(const char * fontname,char * family_name,char * weight_name,char * slant,char * stylename,char * squeeze,char * sffamily,char * sfweight)431 static void decomposename(const char *fontname, char *family_name, char *weight_name,
432 char *slant, char *stylename, char *squeeze, char *sffamily, char *sfweight ) {
433 char *ital, *bold, *style, *compress;
434 char ich='\0', bch='\0', sch='\0', cch='\0';
435 char *pt;
436
437 if ( *fontname=='-' ) {
438 sscanf(fontname,"-%*[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]",
439 family_name,weight_name,slant,squeeze,stylename);
440 } else {
441 /* Assume it's a fontographer type name */
442 strcpy(slant,"R");
443 strcpy(squeeze,"Normal");
444 /* Sigh. I don't use "Italic" and "Oblique" because urw truncates these to 4 */
445 /* characters each. */
446 if (( ital = strstrmatch(fontname,"Ital"))!=NULL )
447 strcpy(slant,"I");
448 else if (( ital = strstrmatch(fontname,"Kurs"))!=NULL )
449 strcpy(slant,"I");
450 else if (( ital = strstr(fontname,"Obli"))!=NULL )
451 strcpy(slant,"O");
452 else if (( ital = strstr(fontname,"Slanted"))!=NULL )
453 strcpy(slant,"O");
454 /* The XLFD spec also supports RI and RO (reverse skewed italic/oblique) */
455
456 if (( bold = strstr(fontname,"Bold"))==NULL &&
457 ( bold = strstr(fontname,"Ligh"))==NULL &&
458 ( bold = strstr(fontname,"Demi"))==NULL &&
459 ( bold = strstr(fontname,"Blac"))==NULL &&
460 ( bold = strstr(fontname,"Roma"))==NULL &&
461 ( bold = strstr(fontname,"Book"))==NULL &&
462 ( bold = strstr(fontname,"Regu"))==NULL &&
463 ( bold = strstr(fontname,"Medi"))==NULL )
464 {
465 /* Again, URW */
466 ;
467 }
468
469 if (( style = strstr(fontname,"Sans"))==NULL &&
470 (compress = strstr(fontname,"SmallCaps"))==NULL )
471 {
472 ;
473 }
474 if ((compress = strstr(fontname,"Extended"))==NULL &&
475 (compress = strstr(fontname,"Condensed"))==NULL )
476 {
477 ;
478 }
479
480 strcpy(weight_name,"Medium");
481 *stylename='\0';
482 if ( bold!=NULL ) { bch = *bold; *bold = '\0'; }
483 if ( ital!=NULL ) { ich = *ital; *ital = '\0'; }
484 if ( style!=NULL ) { sch = *style; *style = '\0'; }
485 if ( compress!=NULL ) { cch = *compress; *compress = '\0'; }
486 strcpy(family_name,fontname);
487 if ( bold!=NULL ) {
488 *bold = bch;
489 strcpy(weight_name,bold);
490 *bold = '\0';
491 }
492 if ( sfweight!=NULL && *sfweight!='\0' )
493 strcpy(weight_name,sfweight);
494 if ( style!=NULL ) {
495 *style = sch;
496 strcpy(stylename,style);
497 *style = '\0';
498 }
499 if ( compress!=NULL ) {
500 *compress = cch;
501 strcpy(squeeze,compress);
502 }
503 if ( style!=NULL ) *style = sch;
504 if ( bold!=NULL ) *bold = bch;
505 if ( ital!=NULL ) *ital = ich;
506 }
507 if ( sffamily!=NULL && *sffamily!='\0' )
508 strcpy(family_name,sffamily);
509 while ( (pt=strchr(family_name,'-'))!=NULL )
510 strcpy(pt,pt+1);
511 }
512
getcomponent(const char * xlfd,char * pt,int maxlen)513 static const char *getcomponent(const char *xlfd,char *pt,int maxlen) {
514 char *end = pt+maxlen-1;
515
516 while ( *xlfd!='-' && *xlfd!='\0' && pt<end )
517 *pt++ = *xlfd++;
518 while ( *xlfd!='-' && *xlfd!='\0' )
519 ++xlfd;
520 *pt = '\0';
521 return( xlfd );
522 }
523
XLFD_GetComponents(const char * xlfd,struct xlfd_components * components)524 void XLFD_GetComponents(const char *xlfd, struct xlfd_components *components) {
525 /* can't use sscanf because it fails if %[^-] matches an empty string */
526
527 memset(components,0,sizeof(*components));
528
529 if ( *xlfd=='-' )
530 xlfd = getcomponent(xlfd+1,components->foundry,sizeof(components->foundry));
531 if ( *xlfd=='-' )
532 xlfd = getcomponent(xlfd+1,components->family,sizeof(components->family));
533 if ( *xlfd=='-' )
534 xlfd = getcomponent(xlfd+1,components->weight,sizeof(components->weight));
535 if ( *xlfd=='-' )
536 xlfd = getcomponent(xlfd+1,components->slant,sizeof(components->slant));
537 if ( *xlfd=='-' )
538 xlfd = getcomponent(xlfd+1,components->setwidth,sizeof(components->setwidth));
539 if ( *xlfd=='-' )
540 xlfd = getcomponent(xlfd+1,components->add_style,sizeof(components->add_style));
541 if ( *xlfd=='-' )
542 components->pixel_size = strtol(xlfd+1,(char **)&xlfd,10);
543 if ( *xlfd=='-' )
544 components->point_size = strtol(xlfd+1,(char **)&xlfd,10);
545 if ( *xlfd=='-' )
546 components->res_x = strtol(xlfd+1,(char **)&xlfd,10);
547 if ( *xlfd=='-' )
548 components->res_y = strtol(xlfd+1,(char **)&xlfd,10);
549 if ( *xlfd=='-' )
550 xlfd = getcomponent(xlfd+1,components->spacing,sizeof(components->spacing));
551 if ( *xlfd=='-' )
552 components->avg_width = strtol(xlfd+1,(char **)&xlfd,10);
553 if ( *xlfd=='-' )
554 xlfd = getcomponent(xlfd+1,components->cs_reg,sizeof(components->cs_reg));
555 if ( *xlfd=='-' )
556 xlfd = getcomponent(xlfd+1,components->cs_enc,sizeof(components->cs_enc));
557 }
558
XLFD_CreateComponents(BDFFont * font,EncMap * map,int res,struct xlfd_components * components)559 void XLFD_CreateComponents(BDFFont *font,EncMap *map, int res, struct xlfd_components *components) {
560 int avg, cnt, pnt;
561 const char *mono;
562 char family_name[80], weight_name[60], slant[10], stylename[40], squeeze[40];
563 const char *sffn = *font->sf->fontname ? font->sf->fontname : "Untitled";
564 char reg[100], enc[40];
565 int old_res;
566
567 mono = AllSame(font,&avg,&cnt);
568 old_res = BdfPropHasInt(font,"RESOLUTION_X",-1);
569 if ( res!=-1 )
570 /* Already set */;
571 else if ( old_res>0 )
572 res = old_res;
573 else if ( font->res>0 )
574 res = font->res;
575 else if ( font->pixelsize==33 || font->pixelsize==28 || font->pixelsize==17 || font->pixelsize==14 )
576 res = 100;
577 else
578 res = 75;
579
580 pnt = ((font->pixelsize*72+res/2)/res)*10;
581 if ( pnt==230 && res==75 )
582 pnt = 240;
583
584 decomposename(sffn, family_name, weight_name, slant,
585 stylename, squeeze, font->sf->familyname, font->sf->weight);
586 def_Charset_Enc(map,reg,enc);
587 strncpy(components->foundry,
588 BdfPropHasString(font,"FOUNDRY", font->foundry!=NULL?font->foundry:BDFFoundry==NULL?copy("FontForge"):BDFFoundry),sizeof(components->foundry));
589 strncpy(components->family,
590 BdfPropHasString(font,"FAMILY_NAME", family_name),sizeof(components->family));
591 strncpy(components->weight,
592 BdfPropHasString(font,"WEIGHT_NAME", weight_name),sizeof(components->weight));
593 strncpy(components->slant,
594 BdfPropHasString(font,"SLANT", slant),sizeof(components->slant));
595 strncpy(components->setwidth,
596 BdfPropHasString(font,"SETWIDTH_NAME", squeeze),sizeof(components->setwidth));
597 strncpy(components->add_style,
598 BdfPropHasString(font,"ADD_STYLE_NAME", stylename),sizeof(components->add_style));
599 components->pixel_size = font->pixelsize;
600 components->point_size = res==old_res ? BdfPropHasInt(font,"POINT_SIZE", pnt) : pnt;
601 components->res_x = res;
602 components->res_y = res;
603 strncpy(components->spacing,
604 BdfPropHasString(font,"SPACING", mono),sizeof(components->spacing));
605 components->avg_width = avg;
606 strncpy(components->cs_reg,
607 BdfPropHasString(font,"CHARSET_REGISTRY", reg),sizeof(components->cs_reg));
608 strncpy(components->cs_enc,
609 BdfPropHasString(font,"CHARSET_ENCODING", enc),sizeof(components->cs_enc));
610
611 components->foundry[sizeof(components->foundry)-1] = '\0';
612 components->family[sizeof(components->family)-1] = '\0';
613 components->weight[sizeof(components->weight)-1] = '\0';
614 components->slant[sizeof(components->slant)-1] = '\0';
615 components->setwidth[sizeof(components->setwidth)-1] = '\0';
616 components->add_style[sizeof(components->add_style)-1] = '\0';
617 components->spacing[sizeof(components->spacing)-1] = '\0';
618 components->cs_reg[sizeof(components->cs_reg)-1] = '\0';
619 components->cs_enc[sizeof(components->cs_enc)-1] = '\0';
620
621 components->char_cnt = cnt;
622 }
623
Default_XLFD(BDFFont * bdf,EncMap * map,int res)624 void Default_XLFD(BDFFont *bdf,EncMap *map, int res) {
625 char buffer[800];
626 struct xlfd_components components;
627
628 XLFD_CreateComponents(bdf,map, res, &components);
629 snprintf( buffer, sizeof(buffer), "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s",
630 components.foundry,
631 components.family,
632 components.weight,
633 components.slant,
634 components.setwidth,
635 components.add_style,
636 components.pixel_size,
637 components.point_size,
638 components.res_x,
639 components.res_y,
640 components.spacing,
641 components.avg_width,
642 components.cs_reg,
643 components.cs_enc);
644 BDFPropAddString(bdf,"FONT",buffer,NULL);
645 }
646
Default_Properties(BDFFont * bdf,EncMap * map,char * onlyme)647 void Default_Properties(BDFFont *bdf,EncMap *map,char *onlyme) {
648 const char *xlfd = BdfPropHasString(bdf,"FONT",NULL);
649 struct xlfd_components components;
650 int x_h= -1, cap_h= -1, def_ch=-1, gid;
651
652 if ( (gid=SFFindExistingSlot(bdf->sf,'x',NULL))!=-1 && bdf->glyphs[gid]!=NULL ) {
653 x_h = bdf->glyphs[gid]->ymax;
654 }
655 if ( 'X'<map->enccount && (gid=map->map['X'])!=-1 && bdf->glyphs[gid]!=NULL ) {
656 cap_h = bdf->glyphs[gid]->ymax;
657 }
658 def_ch = SFFindNotdef(bdf->sf,-2);
659 if ( def_ch!=-1 ) {
660 def_ch = map->map[def_ch]; /* BDF works on the encoding, not on gids, so the default char must be encoded to be useful */
661 if ( def_ch>=map->enc->char_cnt )
662 def_ch = -1;
663 }
664
665 if ( xlfd!=NULL )
666 XLFD_GetComponents(xlfd,&components);
667 else
668 XLFD_CreateComponents(bdf,map, -1, &components);
669 BDFPropAddString(bdf,"FOUNDRY",components.foundry,onlyme);
670 BDFPropAddString(bdf,"FAMILY_NAME",components.family,onlyme);
671 BDFPropAddString(bdf,"WEIGHT_NAME",components.weight,onlyme);
672 BDFPropAddString(bdf,"SLANT",components.slant,onlyme);
673 BDFPropAddString(bdf,"SETWIDTH_NAME",components.setwidth,onlyme);
674 BDFPropAddString(bdf,"ADD_STYLE_NAME",components.add_style,onlyme);
675 BDFPropAddInt(bdf,"PIXEL_SIZE",bdf->pixelsize,onlyme);
676 BDFPropAddInt(bdf,"POINT_SIZE",components.point_size,onlyme);
677 BDFPropAddInt(bdf,"RESOLUTION_X",components.res_x,onlyme);
678 BDFPropAddInt(bdf,"RESOLUTION_Y",components.res_y,onlyme);
679 BDFPropAddString(bdf,"SPACING",components.spacing,onlyme);
680 BDFPropAddInt(bdf,"AVERAGE_WIDTH",components.avg_width,onlyme);
681 BDFPropAddString(bdf,"CHARSET_REGISTRY",components.cs_reg,onlyme);
682 BDFPropAddString(bdf,"CHARSET_ENCODING",components.cs_enc,onlyme);
683
684 BDFPropAddString(bdf,"FONTNAME_REGISTRY","",onlyme);
685 {
686 char buffer[250];
687 def_Charset_Col(bdf->sf,map, buffer);
688 BDFPropAddString(bdf,"CHARSET_COLLECTIONS", buffer,onlyme );
689 }
690
691 if ( bdf->clut!=NULL )
692 BDFPropAddInt( bdf, "BITS_PER_PIXEL", BDFDepth(bdf),onlyme);
693 BDFPropAddString(bdf,"FONT_NAME",bdf->sf->fontname,onlyme);
694 BDFPropAddString(bdf,"FACE_NAME",bdf->sf->fullname,onlyme); /* Used to be FULL_NAME */
695 if ( bdf->sf->copyright!=NULL ) {
696 char *pt = strchr(bdf->sf->copyright,'\n'), *new;
697 if ( pt==NULL )
698 BDFPropAddString(bdf,"COPYRIGHT",bdf->sf->copyright,onlyme);
699 else {
700 new = copyn(bdf->sf->copyright,pt-bdf->sf->copyright);
701 BDFPropAddString(bdf,"COPYRIGHT",new,onlyme);
702 free(new);
703 }
704 }
705 if ( bdf->sf->version!=NULL )
706 BDFPropAddString(bdf,"FONT_VERSION",bdf->sf->version,onlyme );
707 BDFPropAddInt(bdf,"FONT_ASCENT",bdf->ascent,onlyme);
708 BDFPropAddInt(bdf,"FONT_DESCENT",bdf->descent,onlyme);
709 BDFPropAddInt(bdf,"UNDERLINE_POSITION",
710 (int) rint((bdf->sf->upos*bdf->pixelsize)/(bdf->sf->ascent+bdf->sf->descent)),onlyme);
711 BDFPropAddInt(bdf,"UNDERLINE_THICKNESS",
712 (int) ceil((bdf->sf->uwidth*bdf->pixelsize)/(bdf->sf->ascent+bdf->sf->descent)),onlyme);
713
714 if ( x_h!=-1 )
715 BDFPropAddInt(bdf, "X_HEIGHT", x_h,onlyme );
716 if ( cap_h!=-1 )
717 BDFPropAddInt(bdf, "CAP_HEIGHT", cap_h,onlyme );
718 if ( def_ch!=-1 )
719 BDFPropAddInt(bdf, "DEFAULT_CHAR", def_ch,onlyme );
720 BDFPropAddInt(bdf,"RAW_ASCENT",bdf->sf->ascent*1000/(bdf->sf->ascent+bdf->sf->descent),onlyme);
721 BDFPropAddInt(bdf,"RAW_DESCENT",bdf->sf->descent*1000/(bdf->sf->ascent+bdf->sf->descent),onlyme);
722 if ( bdf->sf->italicangle!=0 )
723 BDFPropAddInt(bdf,"ITALIC_ANGLE",(int) ((90+bdf->sf->italicangle)*64),onlyme);
724
725 if ( (gid=SFFindExistingSlot(bdf->sf,' ',NULL))!=-1 && bdf->glyphs[gid]!=NULL )
726 BDFPropAddInt(bdf,"NORM_SPACE",bdf->glyphs[gid]->width,onlyme);
727
728 if ( onlyme!=NULL ) {
729 /* Only generate these oddities if they ask for them... */
730 if ( strmatch(onlyme,"QUAD_WIDTH")==0 ) /* Depreciated */
731 BDFPropAddInt(bdf,"QUAD_WIDTH",bdf->pixelsize,onlyme);
732 if ( components.res_x==components.res_y ) /* Depreciated */
733 /* This isn't dpi (why not???!), it is 1/100 pixels per point */
734 BDFPropAddInt(bdf,"RESOLUTION",7227/components.res_y,onlyme);
735 }
736
737 if ( bdf->sf->pfminfo.pfmset ) {
738 /* Only generate these if the user has set them with font info */
739 /* OS/2 uses values 0-900. XLFD uses 0-90 */
740 BDFPropAddInt(bdf,"RELATIVE_WEIGHT",bdf->sf->pfminfo.weight/10,onlyme);
741 BDFPropAddInt(bdf,"RELATIVE_SETWIDTH",bdf->sf->pfminfo.width*10,onlyme);
742 }
743 if ( bdf->sf->pfminfo.subsuper_set ) {
744 BDFPropAddInt(bdf,"SUPERSCRIPT_X",
745 bdf->sf->pfminfo.os2_supxoff*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
746 onlyme);
747 BDFPropAddInt(bdf,"SUPERSCRIPT_Y",
748 bdf->sf->pfminfo.os2_supyoff*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
749 onlyme);
750 BDFPropAddInt(bdf,"SUPERSCRIPT_SIZE",
751 bdf->sf->pfminfo.os2_supysize*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
752 onlyme);
753 BDFPropAddInt(bdf,"SUBSCRIPT_X",
754 bdf->sf->pfminfo.os2_subxoff*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
755 onlyme);
756 BDFPropAddInt(bdf,"SUBSCRIPT_Y",
757 bdf->sf->pfminfo.os2_subyoff*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
758 onlyme);
759 BDFPropAddInt(bdf,"SUBSCRIPT_SIZE",
760 bdf->sf->pfminfo.os2_subysize*bdf->pixelsize/(bdf->sf->ascent+bdf->sf->descent),
761 onlyme);
762 }
763
764 {
765 const char *selection = "0123456789$";
766 int width=-1;
767 while ( *selection!='\0' ) {
768 if ( (gid=SFFindExistingSlot(bdf->sf,*selection,NULL))!=-1 &&
769 bdf->glyphs[gid]!=NULL ) {
770 if ( width==-1 )
771 width = bdf->glyphs[gid]->width;
772 else if ( width!=bdf->glyphs[gid]->width )
773 width = -2;
774 }
775 ++selection;
776 }
777 if ( width!=-2 )
778 BDFPropAddInt(bdf,"FIGURE_WIDTH",width,onlyme);
779 }
780
781 {
782 int gid;
783 int lc_cnt, lc_sum, uc_cnt, uc_sum;
784 BDFChar *bdfc;
785
786 lc_cnt = lc_sum = uc_cnt = uc_sum = 0;
787 for ( gid = 0; gid<bdf->glyphcnt; ++gid ) if ( (bdfc=bdf->glyphs[gid])!=NULL ) {
788 SplineChar *sc = bdfc->sc;
789 if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && islower(sc->unicodeenc ) ) {
790 ++lc_cnt;
791 lc_sum += bdfc->width;
792 }
793 if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && isupper(sc->unicodeenc ) ) {
794 ++uc_cnt;
795 uc_sum += bdfc->width;
796 }
797 }
798 if ( lc_cnt!=0 )
799 BDFPropAddInt(bdf,"AVG_LOWERCASE_WIDTH",lc_sum*10/lc_cnt,onlyme);
800 if ( uc_cnt!=0 )
801 BDFPropAddInt(bdf,"AVG_UPPERCASE_WIDTH",uc_sum*10/uc_cnt,onlyme);
802 }
803
804 /* MIN_SPACE, MAX_SPACE & END_SPACE are judgement calls and I shan't default them */
805 /* also SMALL_CAP_SIZE, STRIKEOUT_ASCENT, STRIKEOUT_DESCENT, DESTINATION */
806 /* WEIGHT requires a knowlege of stem sizes and I'm not going to do that */
807 /* much analysis */
808 /* NOTICE is very similar to copyright. */
809 /* FONT_TYPE, RASTERIZER_NAME, RASTERIZER_VERSION */
810 /* RAW_* I only provide ASCENT & DESCENT */
811 /* AXIS_NAMES, AXIS_LIMITS, AXIS_TYPES for mm fonts */
812 }
813
BDFDefaultProps(BDFFont * bdf,EncMap * map,int res)814 void BDFDefaultProps(BDFFont *bdf, EncMap *map, int res) {
815 char *start, *end, *temp;
816
817 bdf->prop_max = bdf->prop_cnt;
818
819 Default_XLFD(bdf,map,res);
820
821 if ( bdf->sf->copyright!=NULL ) {
822 start = bdf->sf->copyright;
823 while ( (end=strchr(start,'\n'))!=NULL ) {
824 temp = copyn(start,end-start );
825 BDFPropAppendString(bdf,"COMMENT", temp);
826 free( temp );
827 start = end+1;
828 }
829 if ( *start!='\0' )
830 BDFPropAppendString(bdf,"COMMENT", start );
831 }
832 Default_Properties(bdf,map,NULL);
833 }
834
BDFMakeGID(BDFFont * bdf,int gid)835 BDFChar *BDFMakeGID(BDFFont *bdf,int gid) {
836 SplineFont *sf=bdf->sf;
837 SplineChar *sc;
838 BDFChar *bc;
839 int i;
840
841 if ( gid==-1 )
842 return( NULL );
843
844 if ( sf->cidmaster!=NULL || sf->subfonts!=NULL ) {
845 int j = SFHasCID(sf,gid);
846 if ( sf->cidmaster ) sf = sf->cidmaster;
847 if ( j==-1 ) {
848 for ( j=0; j<sf->subfontcnt; ++j )
849 if ( gid<sf->subfonts[j]->glyphcnt )
850 break;
851 if ( j==sf->subfontcnt )
852 return( NULL );
853 }
854 sf = sf->subfonts[j];
855 }
856 if ( (sc = sf->glyphs[gid])==NULL )
857 return( NULL );
858
859 if ( gid>=bdf->glyphcnt ) {
860 if ( gid>=bdf->glyphmax )
861 bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=sf->glyphmax)*sizeof(BDFChar *));
862 for ( i=bdf->glyphcnt; i<=gid; ++i )
863 bdf->glyphs[i] = NULL;
864 bdf->glyphcnt = sf->glyphcnt;
865 }
866 if ( (bc = bdf->glyphs[gid])==NULL ) {
867 if ( use_freetype_to_rasterize_fv ) {
868 void *freetype_context = FreeTypeFontContext(sf,sc,NULL,ly_fore);
869 if ( freetype_context != NULL ) {
870 bc = SplineCharFreeTypeRasterize(freetype_context,
871 sc->orig_pos,bdf->pixelsize,72,bdf->clut?8:1);
872 FreeTypeFreeContext(freetype_context);
873 }
874 }
875 if ( bc!=NULL )
876 /* Done */;
877 else if ( bdf->clut==NULL )
878 bc = SplineCharRasterize(sc,ly_fore,bdf->pixelsize);
879 else
880 bc = SplineCharAntiAlias(sc,ly_fore,bdf->pixelsize,BDFDepth(bdf));
881 bdf->glyphs[gid] = bc;
882 bc->orig_pos = gid;
883 BCCharChangedUpdate(bc);
884 }
885 return( bc );
886 }
887
BDFMakeChar(BDFFont * bdf,EncMap * map,int enc)888 BDFChar *BDFMakeChar(BDFFont *bdf,EncMap *map,int enc) {
889 SplineFont *sf=bdf->sf;
890
891 if ( enc==-1 )
892 return( NULL );
893
894 if ( sf->cidmaster!=NULL ) {
895 int j = SFHasCID(sf,enc);
896 sf = sf->cidmaster;
897 if ( j==-1 ) {
898 for ( j=0; j<sf->subfontcnt; ++j )
899 if ( enc<sf->subfonts[j]->glyphcnt )
900 break;
901 if ( j==sf->subfontcnt )
902 return( NULL );
903 }
904 sf = sf->subfonts[j];
905 }
906 SFMakeChar(sf,map,enc);
907 return( BDFMakeGID(bdf,map->map[enc]));
908 }
909
BCClearAll(BDFChar * bc)910 void BCClearAll(BDFChar *bc) {
911 BDFRefChar *head,*cur;
912
913 if ( bc==NULL )
914 return;
915 for ( head = bc->refs; head != NULL; ) {
916 cur = head; head = head->next; free( cur );
917 }
918 bc->refs = NULL;
919
920 BCPreserveState(bc);
921 BCFlattenFloat(bc);
922 memset(bc->bitmap,'\0',bc->bytes_per_line*(bc->ymax-bc->ymin+1));
923 BCCompressBitmap(bc);
924 bc->xmin = 0; bc->xmax = 0;
925 bc->ymin = 0; bc->ymax = 0;
926 BCCharChangedUpdate(bc);
927 }
928
BCChngNoUpdate(BDFChar * bc)929 static void BCChngNoUpdate(BDFChar *bc) {
930 bc->changed = true;
931 bc->sc->parent->changed = true;
932 }
933
BCNoUpdate(BDFChar * UNUSED (bc))934 static void BCNoUpdate(BDFChar *UNUSED(bc)) {
935 }
936
BCNothingDestroyed(BDFChar * UNUSED (bc))937 static void BCNothingDestroyed(BDFChar *UNUSED(bc)) {
938 }
939
940 static struct bc_interface noui_bc = {
941 BCChngNoUpdate,
942 BCNoUpdate,
943 BCNothingDestroyed
944 };
945
946 struct bc_interface *bc_interface = &noui_bc;
947
FF_SetBCInterface(struct bc_interface * bci)948 void FF_SetBCInterface(struct bc_interface *bci) {
949 bc_interface = bci;
950 }
951