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