1 /* |
|
2 * Copyright 2000 Computing Research Labs, New Mexico State University |
|
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 |
|
4 * Francesco Zappa Nardelli |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a |
|
7 * copy of this software and associated documentation files (the "Software"), |
|
8 * to deal in the Software without restriction, including without limitation |
|
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
10 * and/or sell copies of the Software, and to permit persons to whom the |
|
11 * Software is furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY |
|
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT |
|
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR |
|
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
23 */ |
|
24 |
|
25 /*************************************************************************/ |
|
26 /* */ |
|
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */ |
|
28 /* */ |
|
29 /* taken from Mark Leisher's xmbdfed package */ |
|
30 /* */ |
|
31 /*************************************************************************/ |
|
32 |
|
33 |
|
34 #include <ft2build.h> |
|
35 |
|
36 #include FT_FREETYPE_H |
|
37 #include FT_INTERNAL_DEBUG_H |
|
38 #include FT_INTERNAL_STREAM_H |
|
39 #include FT_INTERNAL_OBJECTS_H |
|
40 |
|
41 #include "bdf.h" |
|
42 #include "bdferror.h" |
|
43 |
|
44 |
|
45 /*************************************************************************/ |
|
46 /* */ |
|
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
49 /* messages during execution. */ |
|
50 /* */ |
|
51 #undef FT_COMPONENT |
|
52 #define FT_COMPONENT trace_bdflib |
|
53 |
|
54 |
|
55 /*************************************************************************/ |
|
56 /* */ |
|
57 /* Default BDF font options. */ |
|
58 /* */ |
|
59 /*************************************************************************/ |
|
60 |
|
61 |
|
62 static const bdf_options_t _bdf_opts = |
|
63 { |
|
64 1, /* Correct metrics. */ |
|
65 1, /* Preserve unencoded glyphs. */ |
|
66 0, /* Preserve comments. */ |
|
67 BDF_PROPORTIONAL /* Default spacing. */ |
|
68 }; |
|
69 |
|
70 |
|
71 /*************************************************************************/ |
|
72 /* */ |
|
73 /* Builtin BDF font properties. */ |
|
74 /* */ |
|
75 /*************************************************************************/ |
|
76 |
|
77 /* List of most properties that might appear in a font. Doesn't include */ |
|
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ |
|
79 |
|
80 static const bdf_property_t _bdf_properties[] = |
|
81 { |
|
82 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, |
|
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, |
|
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, |
|
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, |
|
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, |
|
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } }, |
|
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } }, |
|
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, |
|
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } }, |
|
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, |
|
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } }, |
|
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } }, |
|
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } }, |
|
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, |
|
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, |
|
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, |
|
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } }, |
|
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } }, |
|
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, |
|
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } }, |
|
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, |
|
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, |
|
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, |
|
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, |
|
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, |
|
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, |
|
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, |
|
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, |
|
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, |
|
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, |
|
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, |
|
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, |
|
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, |
|
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, |
|
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, |
|
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, |
|
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, |
|
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, |
|
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } }, |
|
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, |
|
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, |
|
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, |
|
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } }, |
|
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } }, |
|
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, |
|
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, |
|
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, |
|
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, |
|
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, |
|
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, |
|
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, |
|
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, |
|
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, |
|
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } }, |
|
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, |
|
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } }, |
|
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, |
|
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, |
|
165 }; |
|
166 |
|
167 static const unsigned long |
|
168 _num_bdf_properties = sizeof ( _bdf_properties ) / |
|
169 sizeof ( _bdf_properties[0] ); |
|
170 |
|
171 |
|
172 /*************************************************************************/ |
|
173 /* */ |
|
174 /* Hash table utilities for the properties. */ |
|
175 /* */ |
|
176 /*************************************************************************/ |
|
177 |
|
178 /* XXX: Replace this with FreeType's hash functions */ |
|
179 |
|
180 |
|
181 #define INITIAL_HT_SIZE 241 |
|
182 |
|
183 typedef void |
|
184 (*hash_free_func)( hashnode node ); |
|
185 |
|
186 static hashnode* |
|
187 hash_bucket( const char* key, |
|
188 hashtable* ht ) |
|
189 { |
|
190 const char* kp = key; |
|
191 unsigned long res = 0; |
|
192 hashnode* bp = ht->table, *ndp; |
|
193 |
|
194 |
|
195 /* Mocklisp hash function. */ |
|
196 while ( *kp ) |
|
197 res = ( res << 5 ) - res + *kp++; |
|
198 |
|
199 ndp = bp + ( res % ht->size ); |
|
200 while ( *ndp ) |
|
201 { |
|
202 kp = (*ndp)->key; |
|
203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 ) |
|
204 break; |
|
205 ndp--; |
|
206 if ( ndp < bp ) |
|
207 ndp = bp + ( ht->size - 1 ); |
|
208 } |
|
209 |
|
210 return ndp; |
|
211 } |
|
212 |
|
213 |
|
214 static FT_Error |
|
215 hash_rehash( hashtable* ht, |
|
216 FT_Memory memory ) |
|
217 { |
|
218 hashnode* obp = ht->table, *bp, *nbp; |
|
219 int i, sz = ht->size; |
|
220 FT_Error error = BDF_Err_Ok; |
|
221 |
|
222 |
|
223 ht->size <<= 1; |
|
224 ht->limit = ht->size / 3; |
|
225 |
|
226 if ( FT_NEW_ARRAY( ht->table, ht->size ) ) |
|
227 goto Exit; |
|
228 |
|
229 for ( i = 0, bp = obp; i < sz; i++, bp++ ) |
|
230 { |
|
231 if ( *bp ) |
|
232 { |
|
233 nbp = hash_bucket( (*bp)->key, ht ); |
|
234 *nbp = *bp; |
|
235 } |
|
236 } |
|
237 FT_FREE( obp ); |
|
238 |
|
239 Exit: |
|
240 return error; |
|
241 } |
|
242 |
|
243 |
|
244 static FT_Error |
|
245 hash_init( hashtable* ht, |
|
246 FT_Memory memory ) |
|
247 { |
|
248 int sz = INITIAL_HT_SIZE; |
|
249 FT_Error error = BDF_Err_Ok; |
|
250 |
|
251 |
|
252 ht->size = sz; |
|
253 ht->limit = sz / 3; |
|
254 ht->used = 0; |
|
255 |
|
256 if ( FT_NEW_ARRAY( ht->table, sz ) ) |
|
257 goto Exit; |
|
258 |
|
259 Exit: |
|
260 return error; |
|
261 } |
|
262 |
|
263 |
|
264 static void |
|
265 hash_free( hashtable* ht, |
|
266 FT_Memory memory ) |
|
267 { |
|
268 if ( ht != 0 ) |
|
269 { |
|
270 int i, sz = ht->size; |
|
271 hashnode* bp = ht->table; |
|
272 |
|
273 |
|
274 for ( i = 0; i < sz; i++, bp++ ) |
|
275 FT_FREE( *bp ); |
|
276 |
|
277 FT_FREE( ht->table ); |
|
278 } |
|
279 } |
|
280 |
|
281 |
|
282 static FT_Error |
|
283 hash_insert( char* key, |
|
284 size_t data, |
|
285 hashtable* ht, |
|
286 FT_Memory memory ) |
|
287 { |
|
288 hashnode nn, *bp = hash_bucket( key, ht ); |
|
289 FT_Error error = BDF_Err_Ok; |
|
290 |
|
291 |
|
292 nn = *bp; |
|
293 if ( !nn ) |
|
294 { |
|
295 if ( FT_NEW( nn ) ) |
|
296 goto Exit; |
|
297 *bp = nn; |
|
298 |
|
299 nn->key = key; |
|
300 nn->data = data; |
|
301 |
|
302 if ( ht->used >= ht->limit ) |
|
303 { |
|
304 error = hash_rehash( ht, memory ); |
|
305 if ( error ) |
|
306 goto Exit; |
|
307 } |
|
308 ht->used++; |
|
309 } |
|
310 else |
|
311 nn->data = data; |
|
312 |
|
313 Exit: |
|
314 return error; |
|
315 } |
|
316 |
|
317 |
|
318 static hashnode |
|
319 hash_lookup( const char* key, |
|
320 hashtable* ht ) |
|
321 { |
|
322 hashnode *np = hash_bucket( key, ht ); |
|
323 |
|
324 |
|
325 return *np; |
|
326 } |
|
327 |
|
328 |
|
329 /*************************************************************************/ |
|
330 /* */ |
|
331 /* Utility types and functions. */ |
|
332 /* */ |
|
333 /*************************************************************************/ |
|
334 |
|
335 |
|
336 /* Function type for parsing lines of a BDF font. */ |
|
337 |
|
338 typedef FT_Error |
|
339 (*_bdf_line_func_t)( char* line, |
|
340 unsigned long linelen, |
|
341 unsigned long lineno, |
|
342 void* call_data, |
|
343 void* client_data ); |
|
344 |
|
345 |
|
346 /* List structure for splitting lines into fields. */ |
|
347 |
|
348 typedef struct _bdf_list_t_ |
|
349 { |
|
350 char** field; |
|
351 unsigned long size; |
|
352 unsigned long used; |
|
353 FT_Memory memory; |
|
354 |
|
355 } _bdf_list_t; |
|
356 |
|
357 |
|
358 /* Structure used while loading BDF fonts. */ |
|
359 |
|
360 typedef struct _bdf_parse_t_ |
|
361 { |
|
362 unsigned long flags; |
|
363 unsigned long cnt; |
|
364 unsigned long row; |
|
365 |
|
366 short minlb; |
|
367 short maxlb; |
|
368 short maxrb; |
|
369 short maxas; |
|
370 short maxds; |
|
371 |
|
372 short rbearing; |
|
373 |
|
374 char* glyph_name; |
|
375 long glyph_enc; |
|
376 |
|
377 bdf_font_t* font; |
|
378 bdf_options_t* opts; |
|
379 |
|
380 unsigned long have[2048]; |
|
381 _bdf_list_t list; |
|
382 |
|
383 FT_Memory memory; |
|
384 |
|
385 } _bdf_parse_t; |
|
386 |
|
387 |
|
388 #define setsbit( m, cc ) \ |
|
389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) |
|
390 #define sbitset( m, cc ) \ |
|
391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) |
|
392 |
|
393 |
|
394 static void |
|
395 _bdf_list_init( _bdf_list_t* list, |
|
396 FT_Memory memory ) |
|
397 { |
|
398 FT_ZERO( list ); |
|
399 list->memory = memory; |
|
400 } |
|
401 |
|
402 |
|
403 static void |
|
404 _bdf_list_done( _bdf_list_t* list ) |
|
405 { |
|
406 FT_Memory memory = list->memory; |
|
407 |
|
408 |
|
409 if ( memory ) |
|
410 { |
|
411 FT_FREE( list->field ); |
|
412 FT_ZERO( list ); |
|
413 } |
|
414 } |
|
415 |
|
416 |
|
417 static FT_Error |
|
418 _bdf_list_ensure( _bdf_list_t* list, |
|
419 unsigned long num_items ) /* same as _bdf_list_t.used */ |
|
420 { |
|
421 FT_Error error = BDF_Err_Ok; |
|
422 |
|
423 |
|
424 if ( num_items > list->size ) |
|
425 { |
|
426 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */ |
|
427 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4; |
|
428 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); |
|
429 FT_Memory memory = list->memory; |
|
430 |
|
431 |
|
432 if ( oldsize == bigsize ) |
|
433 { |
|
434 error = BDF_Err_Out_Of_Memory; |
|
435 goto Exit; |
|
436 } |
|
437 else if ( newsize < oldsize || newsize > bigsize ) |
|
438 newsize = bigsize; |
|
439 |
|
440 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) ) |
|
441 goto Exit; |
|
442 |
|
443 list->size = newsize; |
|
444 } |
|
445 |
|
446 Exit: |
|
447 return error; |
|
448 } |
|
449 |
|
450 |
|
451 static void |
|
452 _bdf_list_shift( _bdf_list_t* list, |
|
453 unsigned long n ) |
|
454 { |
|
455 unsigned long i, u; |
|
456 |
|
457 |
|
458 if ( list == 0 || list->used == 0 || n == 0 ) |
|
459 return; |
|
460 |
|
461 if ( n >= list->used ) |
|
462 { |
|
463 list->used = 0; |
|
464 return; |
|
465 } |
|
466 |
|
467 for ( u = n, i = 0; u < list->used; i++, u++ ) |
|
468 list->field[i] = list->field[u]; |
|
469 list->used -= n; |
|
470 } |
|
471 |
|
472 |
|
473 /* An empty string for empty fields. */ |
|
474 |
|
475 static const char empty[1] = { 0 }; /* XXX eliminate this */ |
|
476 |
|
477 |
|
478 static char * |
|
479 _bdf_list_join( _bdf_list_t* list, |
|
480 int c, |
|
481 unsigned long *alen ) |
|
482 { |
|
483 unsigned long i, j; |
|
484 char *fp, *dp; |
|
485 |
|
486 |
|
487 *alen = 0; |
|
488 |
|
489 if ( list == 0 || list->used == 0 ) |
|
490 return 0; |
|
491 |
|
492 dp = list->field[0]; |
|
493 for ( i = j = 0; i < list->used; i++ ) |
|
494 { |
|
495 fp = list->field[i]; |
|
496 while ( *fp ) |
|
497 dp[j++] = *fp++; |
|
498 |
|
499 if ( i + 1 < list->used ) |
|
500 dp[j++] = (char)c; |
|
501 } |
|
502 if ( dp != empty ) |
|
503 dp[j] = 0; |
|
504 |
|
505 *alen = j; |
|
506 return dp; |
|
507 } |
|
508 |
|
509 |
|
510 static FT_Error |
|
511 _bdf_list_split( _bdf_list_t* list, |
|
512 char* separators, |
|
513 char* line, |
|
514 unsigned long linelen ) |
|
515 { |
|
516 int mult, final_empty; |
|
517 char *sp, *ep, *end; |
|
518 char seps[32]; |
|
519 FT_Error error = BDF_Err_Ok; |
|
520 |
|
521 |
|
522 /* Initialize the list. */ |
|
523 list->used = 0; |
|
524 |
|
525 /* If the line is empty, then simply return. */ |
|
526 if ( linelen == 0 || line[0] == 0 ) |
|
527 goto Exit; |
|
528 |
|
529 /* In the original code, if the `separators' parameter is NULL or */ |
|
530 /* empty, the list is split into individual bytes. We don't need */ |
|
531 /* this, so an error is signaled. */ |
|
532 if ( separators == 0 || *separators == 0 ) |
|
533 { |
|
534 error = BDF_Err_Invalid_Argument; |
|
535 goto Exit; |
|
536 } |
|
537 |
|
538 /* Prepare the separator bitmap. */ |
|
539 FT_MEM_ZERO( seps, 32 ); |
|
540 |
|
541 /* If the very last character of the separator string is a plus, then */ |
|
542 /* set the `mult' flag to indicate that multiple separators should be */ |
|
543 /* collapsed into one. */ |
|
544 for ( mult = 0, sp = separators; sp && *sp; sp++ ) |
|
545 { |
|
546 if ( *sp == '+' && *( sp + 1 ) == 0 ) |
|
547 mult = 1; |
|
548 else |
|
549 setsbit( seps, *sp ); |
|
550 } |
|
551 |
|
552 /* Break the line up into fields. */ |
|
553 for ( final_empty = 0, sp = ep = line, end = sp + linelen; |
|
554 sp < end && *sp; ) |
|
555 { |
|
556 /* Collect everything that is not a separator. */ |
|
557 for ( ; *ep && !sbitset( seps, *ep ); ep++ ) |
|
558 ; |
|
559 |
|
560 /* Resize the list if necessary. */ |
|
561 if ( list->used == list->size ) |
|
562 { |
|
563 error = _bdf_list_ensure( list, list->used + 1 ); |
|
564 if ( error ) |
|
565 goto Exit; |
|
566 } |
|
567 |
|
568 /* Assign the field appropriately. */ |
|
569 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty; |
|
570 |
|
571 sp = ep; |
|
572 |
|
573 if ( mult ) |
|
574 { |
|
575 /* If multiple separators should be collapsed, do it now by */ |
|
576 /* setting all the separator characters to 0. */ |
|
577 for ( ; *ep && sbitset( seps, *ep ); ep++ ) |
|
578 *ep = 0; |
|
579 } |
|
580 else if ( *ep != 0 ) |
|
581 /* Don't collapse multiple separators by making them 0, so just */ |
|
582 /* make the one encountered 0. */ |
|
583 *ep++ = 0; |
|
584 |
|
585 final_empty = ( ep > sp && *ep == 0 ); |
|
586 sp = ep; |
|
587 } |
|
588 |
|
589 /* Finally, NULL-terminate the list. */ |
|
590 if ( list->used + final_empty >= list->size ) |
|
591 { |
|
592 error = _bdf_list_ensure( list, list->used + final_empty + 1 ); |
|
593 if ( error ) |
|
594 goto Exit; |
|
595 } |
|
596 |
|
597 if ( final_empty ) |
|
598 list->field[list->used++] = (char*)empty; |
|
599 |
|
600 list->field[list->used] = 0; |
|
601 |
|
602 Exit: |
|
603 return error; |
|
604 } |
|
605 |
|
606 |
|
607 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */ |
|
608 |
|
609 |
|
610 static FT_Error |
|
611 _bdf_readstream( FT_Stream stream, |
|
612 _bdf_line_func_t callback, |
|
613 void* client_data, |
|
614 unsigned long *lno ) |
|
615 { |
|
616 _bdf_line_func_t cb; |
|
617 unsigned long lineno, buf_size; |
|
618 int refill, hold, to_skip; |
|
619 ptrdiff_t bytes, start, end, cursor, avail; |
|
620 char* buf = 0; |
|
621 FT_Memory memory = stream->memory; |
|
622 FT_Error error = BDF_Err_Ok; |
|
623 |
|
624 |
|
625 if ( callback == 0 ) |
|
626 { |
|
627 error = BDF_Err_Invalid_Argument; |
|
628 goto Exit; |
|
629 } |
|
630 |
|
631 /* initial size and allocation of the input buffer */ |
|
632 buf_size = 1024; |
|
633 |
|
634 if ( FT_NEW_ARRAY( buf, buf_size ) ) |
|
635 goto Exit; |
|
636 |
|
637 cb = callback; |
|
638 lineno = 1; |
|
639 buf[0] = 0; |
|
640 start = 0; |
|
641 end = 0; |
|
642 avail = 0; |
|
643 cursor = 0; |
|
644 refill = 1; |
|
645 to_skip = NO_SKIP; |
|
646 bytes = 0; /* make compiler happy */ |
|
647 |
|
648 for (;;) |
|
649 { |
|
650 if ( refill ) |
|
651 { |
|
652 bytes = (ptrdiff_t)FT_Stream_TryRead( |
|
653 stream, (FT_Byte*)buf + cursor, |
|
654 (FT_ULong)( buf_size - cursor ) ); |
|
655 avail = cursor + bytes; |
|
656 cursor = 0; |
|
657 refill = 0; |
|
658 } |
|
659 |
|
660 end = start; |
|
661 |
|
662 /* should we skip an optional character like \n or \r? */ |
|
663 if ( start < avail && buf[start] == to_skip ) |
|
664 { |
|
665 start += 1; |
|
666 to_skip = NO_SKIP; |
|
667 continue; |
|
668 } |
|
669 |
|
670 /* try to find the end of the line */ |
|
671 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) |
|
672 end++; |
|
673 |
|
674 /* if we hit the end of the buffer, try shifting its content */ |
|
675 /* or even resizing it */ |
|
676 if ( end >= avail ) |
|
677 { |
|
678 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */ |
|
679 break; /* ignore it then exit */ |
|
680 |
|
681 if ( start == 0 ) |
|
682 { |
|
683 /* this line is definitely too long; try resizing the input */ |
|
684 /* buffer a bit to handle it. */ |
|
685 FT_ULong new_size; |
|
686 |
|
687 |
|
688 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ |
|
689 { |
|
690 error = BDF_Err_Invalid_Argument; |
|
691 goto Exit; |
|
692 } |
|
693 |
|
694 new_size = buf_size * 2; |
|
695 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) |
|
696 goto Exit; |
|
697 |
|
698 cursor = buf_size; |
|
699 buf_size = new_size; |
|
700 } |
|
701 else |
|
702 { |
|
703 bytes = avail - start; |
|
704 |
|
705 FT_MEM_COPY( buf, buf + start, bytes ); |
|
706 |
|
707 cursor = bytes; |
|
708 avail -= bytes; |
|
709 start = 0; |
|
710 } |
|
711 refill = 1; |
|
712 continue; |
|
713 } |
|
714 |
|
715 /* Temporarily NUL-terminate the line. */ |
|
716 hold = buf[end]; |
|
717 buf[end] = 0; |
|
718 |
|
719 /* XXX: Use encoding independent value for 0x1a */ |
|
720 if ( buf[start] != '#' && buf[start] != 0x1a && end > start ) |
|
721 { |
|
722 error = (*cb)( buf + start, end - start, lineno, |
|
723 (void*)&cb, client_data ); |
|
724 /* Redo if we have encountered CHARS without properties. */ |
|
725 if ( error == -1 ) |
|
726 error = (*cb)( buf + start, end - start, lineno, |
|
727 (void*)&cb, client_data ); |
|
728 if ( error ) |
|
729 break; |
|
730 } |
|
731 |
|
732 lineno += 1; |
|
733 buf[end] = (char)hold; |
|
734 start = end + 1; |
|
735 |
|
736 if ( hold == '\n' ) |
|
737 to_skip = '\r'; |
|
738 else if ( hold == '\r' ) |
|
739 to_skip = '\n'; |
|
740 else |
|
741 to_skip = NO_SKIP; |
|
742 } |
|
743 |
|
744 *lno = lineno; |
|
745 |
|
746 Exit: |
|
747 FT_FREE( buf ); |
|
748 return error; |
|
749 } |
|
750 |
|
751 |
|
752 /* XXX: make this work with EBCDIC also */ |
|
753 |
|
754 static const unsigned char a2i[128] = |
|
755 { |
|
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
760 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, |
|
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, |
|
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
764 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
|
767 }; |
|
768 |
|
769 static const unsigned char odigits[32] = |
|
770 { |
|
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, |
|
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
775 }; |
|
776 |
|
777 static const unsigned char ddigits[32] = |
|
778 { |
|
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, |
|
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
783 }; |
|
784 |
|
785 static const unsigned char hdigits[32] = |
|
786 { |
|
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, |
|
788 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, |
|
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
791 }; |
|
792 |
|
793 |
|
794 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) ) |
|
795 |
|
796 |
|
797 /* Routine to convert an ASCII string into an unsigned long integer. */ |
|
798 static unsigned long |
|
799 _bdf_atoul( char* s, |
|
800 char** end, |
|
801 int base ) |
|
802 { |
|
803 unsigned long v; |
|
804 const unsigned char* dmap; |
|
805 |
|
806 |
|
807 if ( s == 0 || *s == 0 ) |
|
808 return 0; |
|
809 |
|
810 /* Make sure the radix is something recognizable. Default to 10. */ |
|
811 switch ( base ) |
|
812 { |
|
813 case 8: |
|
814 dmap = odigits; |
|
815 break; |
|
816 case 16: |
|
817 dmap = hdigits; |
|
818 break; |
|
819 default: |
|
820 base = 10; |
|
821 dmap = ddigits; |
|
822 break; |
|
823 } |
|
824 |
|
825 /* Check for the special hex prefix. */ |
|
826 if ( *s == '0' && |
|
827 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) |
|
828 { |
|
829 base = 16; |
|
830 dmap = hdigits; |
|
831 s += 2; |
|
832 } |
|
833 |
|
834 for ( v = 0; isdigok( dmap, *s ); s++ ) |
|
835 v = v * base + a2i[(int)*s]; |
|
836 |
|
837 if ( end != 0 ) |
|
838 *end = s; |
|
839 |
|
840 return v; |
|
841 } |
|
842 |
|
843 |
|
844 /* Routine to convert an ASCII string into an signed long integer. */ |
|
845 static long |
|
846 _bdf_atol( char* s, |
|
847 char** end, |
|
848 int base ) |
|
849 { |
|
850 long v, neg; |
|
851 const unsigned char* dmap; |
|
852 |
|
853 |
|
854 if ( s == 0 || *s == 0 ) |
|
855 return 0; |
|
856 |
|
857 /* Make sure the radix is something recognizable. Default to 10. */ |
|
858 switch ( base ) |
|
859 { |
|
860 case 8: |
|
861 dmap = odigits; |
|
862 break; |
|
863 case 16: |
|
864 dmap = hdigits; |
|
865 break; |
|
866 default: |
|
867 base = 10; |
|
868 dmap = ddigits; |
|
869 break; |
|
870 } |
|
871 |
|
872 /* Check for a minus sign. */ |
|
873 neg = 0; |
|
874 if ( *s == '-' ) |
|
875 { |
|
876 s++; |
|
877 neg = 1; |
|
878 } |
|
879 |
|
880 /* Check for the special hex prefix. */ |
|
881 if ( *s == '0' && |
|
882 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) |
|
883 { |
|
884 base = 16; |
|
885 dmap = hdigits; |
|
886 s += 2; |
|
887 } |
|
888 |
|
889 for ( v = 0; isdigok( dmap, *s ); s++ ) |
|
890 v = v * base + a2i[(int)*s]; |
|
891 |
|
892 if ( end != 0 ) |
|
893 *end = s; |
|
894 |
|
895 return ( !neg ) ? v : -v; |
|
896 } |
|
897 |
|
898 |
|
899 /* Routine to convert an ASCII string into an signed short integer. */ |
|
900 static short |
|
901 _bdf_atos( char* s, |
|
902 char** end, |
|
903 int base ) |
|
904 { |
|
905 short v, neg; |
|
906 const unsigned char* dmap; |
|
907 |
|
908 |
|
909 if ( s == 0 || *s == 0 ) |
|
910 return 0; |
|
911 |
|
912 /* Make sure the radix is something recognizable. Default to 10. */ |
|
913 switch ( base ) |
|
914 { |
|
915 case 8: |
|
916 dmap = odigits; |
|
917 break; |
|
918 case 16: |
|
919 dmap = hdigits; |
|
920 break; |
|
921 default: |
|
922 base = 10; |
|
923 dmap = ddigits; |
|
924 break; |
|
925 } |
|
926 |
|
927 /* Check for a minus. */ |
|
928 neg = 0; |
|
929 if ( *s == '-' ) |
|
930 { |
|
931 s++; |
|
932 neg = 1; |
|
933 } |
|
934 |
|
935 /* Check for the special hex prefix. */ |
|
936 if ( *s == '0' && |
|
937 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) |
|
938 { |
|
939 base = 16; |
|
940 dmap = hdigits; |
|
941 s += 2; |
|
942 } |
|
943 |
|
944 for ( v = 0; isdigok( dmap, *s ); s++ ) |
|
945 v = (short)( v * base + a2i[(int)*s] ); |
|
946 |
|
947 if ( end != 0 ) |
|
948 *end = s; |
|
949 |
|
950 return (short)( ( !neg ) ? v : -v ); |
|
951 } |
|
952 |
|
953 |
|
954 /* Routine to compare two glyphs by encoding so they can be sorted. */ |
|
955 static int |
|
956 by_encoding( const void* a, |
|
957 const void* b ) |
|
958 { |
|
959 bdf_glyph_t *c1, *c2; |
|
960 |
|
961 |
|
962 c1 = (bdf_glyph_t *)a; |
|
963 c2 = (bdf_glyph_t *)b; |
|
964 |
|
965 if ( c1->encoding < c2->encoding ) |
|
966 return -1; |
|
967 |
|
968 if ( c1->encoding > c2->encoding ) |
|
969 return 1; |
|
970 |
|
971 return 0; |
|
972 } |
|
973 |
|
974 |
|
975 static FT_Error |
|
976 bdf_create_property( char* name, |
|
977 int format, |
|
978 bdf_font_t* font ) |
|
979 { |
|
980 size_t n; |
|
981 bdf_property_t* p; |
|
982 FT_Memory memory = font->memory; |
|
983 FT_Error error = BDF_Err_Ok; |
|
984 |
|
985 |
|
986 /* First check to see if the property has */ |
|
987 /* already been added or not. If it has, then */ |
|
988 /* simply ignore it. */ |
|
989 if ( hash_lookup( name, &(font->proptbl) ) ) |
|
990 goto Exit; |
|
991 |
|
992 if ( FT_RENEW_ARRAY( font->user_props, |
|
993 font->nuser_props, |
|
994 font->nuser_props + 1 ) ) |
|
995 goto Exit; |
|
996 |
|
997 p = font->user_props + font->nuser_props; |
|
998 FT_ZERO( p ); |
|
999 |
|
1000 n = ft_strlen( name ) + 1; |
|
1001 if ( n > FT_ULONG_MAX ) |
|
1002 return BDF_Err_Invalid_Argument; |
|
1003 |
|
1004 if ( FT_NEW_ARRAY( p->name, n ) ) |
|
1005 goto Exit; |
|
1006 |
|
1007 FT_MEM_COPY( (char *)p->name, name, n ); |
|
1008 |
|
1009 p->format = format; |
|
1010 p->builtin = 0; |
|
1011 |
|
1012 n = _num_bdf_properties + font->nuser_props; |
|
1013 |
|
1014 error = hash_insert( p->name, n, &(font->proptbl), memory ); |
|
1015 if ( error ) |
|
1016 goto Exit; |
|
1017 |
|
1018 font->nuser_props++; |
|
1019 |
|
1020 Exit: |
|
1021 return error; |
|
1022 } |
|
1023 |
|
1024 |
|
1025 FT_LOCAL_DEF( bdf_property_t * ) |
|
1026 bdf_get_property( char* name, |
|
1027 bdf_font_t* font ) |
|
1028 { |
|
1029 hashnode hn; |
|
1030 size_t propid; |
|
1031 |
|
1032 |
|
1033 if ( name == 0 || *name == 0 ) |
|
1034 return 0; |
|
1035 |
|
1036 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 ) |
|
1037 return 0; |
|
1038 |
|
1039 propid = hn->data; |
|
1040 if ( propid >= _num_bdf_properties ) |
|
1041 return font->user_props + ( propid - _num_bdf_properties ); |
|
1042 |
|
1043 return (bdf_property_t*)_bdf_properties + propid; |
|
1044 } |
|
1045 |
|
1046 |
|
1047 /*************************************************************************/ |
|
1048 /* */ |
|
1049 /* BDF font file parsing flags and functions. */ |
|
1050 /* */ |
|
1051 /*************************************************************************/ |
|
1052 |
|
1053 |
|
1054 /* Parse flags. */ |
|
1055 |
|
1056 #define _BDF_START 0x0001 |
|
1057 #define _BDF_FONT_NAME 0x0002 |
|
1058 #define _BDF_SIZE 0x0004 |
|
1059 #define _BDF_FONT_BBX 0x0008 |
|
1060 #define _BDF_PROPS 0x0010 |
|
1061 #define _BDF_GLYPHS 0x0020 |
|
1062 #define _BDF_GLYPH 0x0040 |
|
1063 #define _BDF_ENCODING 0x0080 |
|
1064 #define _BDF_SWIDTH 0x0100 |
|
1065 #define _BDF_DWIDTH 0x0200 |
|
1066 #define _BDF_BBX 0x0400 |
|
1067 #define _BDF_BITMAP 0x0800 |
|
1068 |
|
1069 #define _BDF_SWIDTH_ADJ 0x1000 |
|
1070 |
|
1071 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \ |
|
1072 _BDF_ENCODING | \ |
|
1073 _BDF_SWIDTH | \ |
|
1074 _BDF_DWIDTH | \ |
|
1075 _BDF_BBX | \ |
|
1076 _BDF_BITMAP ) |
|
1077 |
|
1078 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL |
|
1079 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL |
|
1080 |
|
1081 |
|
1082 /* Auto correction messages. */ |
|
1083 #define ACMSG1 "FONT_ASCENT property missing. " \ |
|
1084 "Added \"FONT_ASCENT %hd\".\n" |
|
1085 #define ACMSG2 "FONT_DESCENT property missing. " \ |
|
1086 "Added \"FONT_DESCENT %hd\".\n" |
|
1087 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n" |
|
1088 #define ACMSG4 "Font left bearing != actual left bearing. " \ |
|
1089 "Old: %hd New: %hd.\n" |
|
1090 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" |
|
1091 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n" |
|
1092 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n" |
|
1093 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" |
|
1094 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" |
|
1095 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" |
|
1096 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" |
|
1097 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n" |
|
1098 #define ACMSG13 "Glyph %ld extra rows removed.\n" |
|
1099 #define ACMSG14 "Glyph %ld extra columns removed.\n" |
|
1100 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" |
|
1101 |
|
1102 /* Error messages. */ |
|
1103 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n" |
|
1104 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" |
|
1105 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" |
|
1106 #define ERRMSG4 "[line %ld] BBX too big.\n" |
|
1107 |
|
1108 |
|
1109 static FT_Error |
|
1110 _bdf_add_comment( bdf_font_t* font, |
|
1111 char* comment, |
|
1112 unsigned long len ) |
|
1113 { |
|
1114 char* cp; |
|
1115 FT_Memory memory = font->memory; |
|
1116 FT_Error error = BDF_Err_Ok; |
|
1117 |
|
1118 |
|
1119 if ( FT_RENEW_ARRAY( font->comments, |
|
1120 font->comments_len, |
|
1121 font->comments_len + len + 1 ) ) |
|
1122 goto Exit; |
|
1123 |
|
1124 cp = font->comments + font->comments_len; |
|
1125 |
|
1126 FT_MEM_COPY( cp, comment, len ); |
|
1127 cp[len] = '\n'; |
|
1128 |
|
1129 font->comments_len += len + 1; |
|
1130 |
|
1131 Exit: |
|
1132 return error; |
|
1133 } |
|
1134 |
|
1135 |
|
1136 /* Set the spacing from the font name if it exists, or set it to the */ |
|
1137 /* default specified in the options. */ |
|
1138 static FT_Error |
|
1139 _bdf_set_default_spacing( bdf_font_t* font, |
|
1140 bdf_options_t* opts ) |
|
1141 { |
|
1142 size_t len; |
|
1143 char name[256]; |
|
1144 _bdf_list_t list; |
|
1145 FT_Memory memory; |
|
1146 FT_Error error = BDF_Err_Ok; |
|
1147 |
|
1148 |
|
1149 if ( font == 0 || font->name == 0 || font->name[0] == 0 ) |
|
1150 { |
|
1151 error = BDF_Err_Invalid_Argument; |
|
1152 goto Exit; |
|
1153 } |
|
1154 |
|
1155 memory = font->memory; |
|
1156 |
|
1157 _bdf_list_init( &list, memory ); |
|
1158 |
|
1159 font->spacing = opts->font_spacing; |
|
1160 |
|
1161 len = ft_strlen( font->name ) + 1; |
|
1162 /* Limit ourselves to 256 characters in the font name. */ |
|
1163 if ( len >= 256 ) |
|
1164 { |
|
1165 error = BDF_Err_Invalid_Argument; |
|
1166 goto Exit; |
|
1167 } |
|
1168 |
|
1169 FT_MEM_COPY( name, font->name, len ); |
|
1170 |
|
1171 error = _bdf_list_split( &list, (char *)"-", name, len ); |
|
1172 if ( error ) |
|
1173 goto Fail; |
|
1174 |
|
1175 if ( list.used == 15 ) |
|
1176 { |
|
1177 switch ( list.field[11][0] ) |
|
1178 { |
|
1179 case 'C': |
|
1180 case 'c': |
|
1181 font->spacing = BDF_CHARCELL; |
|
1182 break; |
|
1183 case 'M': |
|
1184 case 'm': |
|
1185 font->spacing = BDF_MONOWIDTH; |
|
1186 break; |
|
1187 case 'P': |
|
1188 case 'p': |
|
1189 font->spacing = BDF_PROPORTIONAL; |
|
1190 break; |
|
1191 } |
|
1192 } |
|
1193 |
|
1194 Fail: |
|
1195 _bdf_list_done( &list ); |
|
1196 |
|
1197 Exit: |
|
1198 return error; |
|
1199 } |
|
1200 |
|
1201 |
|
1202 /* Determine whether the property is an atom or not. If it is, then */ |
|
1203 /* clean it up so the double quotes are removed if they exist. */ |
|
1204 static int |
|
1205 _bdf_is_atom( char* line, |
|
1206 unsigned long linelen, |
|
1207 char** name, |
|
1208 char** value, |
|
1209 bdf_font_t* font ) |
|
1210 { |
|
1211 int hold; |
|
1212 char *sp, *ep; |
|
1213 bdf_property_t* p; |
|
1214 |
|
1215 |
|
1216 *name = sp = ep = line; |
|
1217 |
|
1218 while ( *ep && *ep != ' ' && *ep != '\t' ) |
|
1219 ep++; |
|
1220 |
|
1221 hold = -1; |
|
1222 if ( *ep ) |
|
1223 { |
|
1224 hold = *ep; |
|
1225 *ep = 0; |
|
1226 } |
|
1227 |
|
1228 p = bdf_get_property( sp, font ); |
|
1229 |
|
1230 /* Restore the character that was saved before any return can happen. */ |
|
1231 if ( hold != -1 ) |
|
1232 *ep = (char)hold; |
|
1233 |
|
1234 /* If the property exists and is not an atom, just return here. */ |
|
1235 if ( p && p->format != BDF_ATOM ) |
|
1236 return 0; |
|
1237 |
|
1238 /* The property is an atom. Trim all leading and trailing whitespace */ |
|
1239 /* and double quotes for the atom value. */ |
|
1240 sp = ep; |
|
1241 ep = line + linelen; |
|
1242 |
|
1243 /* Trim the leading whitespace if it exists. */ |
|
1244 *sp++ = 0; |
|
1245 while ( *sp && |
|
1246 ( *sp == ' ' || *sp == '\t' ) ) |
|
1247 sp++; |
|
1248 |
|
1249 /* Trim the leading double quote if it exists. */ |
|
1250 if ( *sp == '"' ) |
|
1251 sp++; |
|
1252 *value = sp; |
|
1253 |
|
1254 /* Trim the trailing whitespace if it exists. */ |
|
1255 while ( ep > sp && |
|
1256 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) |
|
1257 *--ep = 0; |
|
1258 |
|
1259 /* Trim the trailing double quote if it exists. */ |
|
1260 if ( ep > sp && *( ep - 1 ) == '"' ) |
|
1261 *--ep = 0; |
|
1262 |
|
1263 return 1; |
|
1264 } |
|
1265 |
|
1266 |
|
1267 static FT_Error |
|
1268 _bdf_add_property( bdf_font_t* font, |
|
1269 char* name, |
|
1270 char* value ) |
|
1271 { |
|
1272 size_t propid; |
|
1273 hashnode hn; |
|
1274 bdf_property_t *prop, *fp; |
|
1275 FT_Memory memory = font->memory; |
|
1276 FT_Error error = BDF_Err_Ok; |
|
1277 |
|
1278 |
|
1279 /* First, check to see if the property already exists in the font. */ |
|
1280 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 ) |
|
1281 { |
|
1282 /* The property already exists in the font, so simply replace */ |
|
1283 /* the value of the property with the current value. */ |
|
1284 fp = font->props + hn->data; |
|
1285 |
|
1286 switch ( fp->format ) |
|
1287 { |
|
1288 case BDF_ATOM: |
|
1289 /* Delete the current atom if it exists. */ |
|
1290 FT_FREE( fp->value.atom ); |
|
1291 |
|
1292 if ( value && value[0] != 0 ) |
|
1293 { |
|
1294 if ( FT_STRDUP( fp->value.atom, value ) ) |
|
1295 goto Exit; |
|
1296 } |
|
1297 break; |
|
1298 |
|
1299 case BDF_INTEGER: |
|
1300 fp->value.l = _bdf_atol( value, 0, 10 ); |
|
1301 break; |
|
1302 |
|
1303 case BDF_CARDINAL: |
|
1304 fp->value.ul = _bdf_atoul( value, 0, 10 ); |
|
1305 break; |
|
1306 |
|
1307 default: |
|
1308 ; |
|
1309 } |
|
1310 |
|
1311 goto Exit; |
|
1312 } |
|
1313 |
|
1314 /* See whether this property type exists yet or not. */ |
|
1315 /* If not, create it. */ |
|
1316 hn = hash_lookup( name, &(font->proptbl) ); |
|
1317 if ( hn == 0 ) |
|
1318 { |
|
1319 error = bdf_create_property( name, BDF_ATOM, font ); |
|
1320 if ( error ) |
|
1321 goto Exit; |
|
1322 hn = hash_lookup( name, &(font->proptbl) ); |
|
1323 } |
|
1324 |
|
1325 /* Allocate another property if this is overflow. */ |
|
1326 if ( font->props_used == font->props_size ) |
|
1327 { |
|
1328 if ( font->props_size == 0 ) |
|
1329 { |
|
1330 if ( FT_NEW_ARRAY( font->props, 1 ) ) |
|
1331 goto Exit; |
|
1332 } |
|
1333 else |
|
1334 { |
|
1335 if ( FT_RENEW_ARRAY( font->props, |
|
1336 font->props_size, |
|
1337 font->props_size + 1 ) ) |
|
1338 goto Exit; |
|
1339 } |
|
1340 |
|
1341 fp = font->props + font->props_size; |
|
1342 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) ); |
|
1343 font->props_size++; |
|
1344 } |
|
1345 |
|
1346 propid = hn->data; |
|
1347 if ( propid >= _num_bdf_properties ) |
|
1348 prop = font->user_props + ( propid - _num_bdf_properties ); |
|
1349 else |
|
1350 prop = (bdf_property_t*)_bdf_properties + propid; |
|
1351 |
|
1352 fp = font->props + font->props_used; |
|
1353 |
|
1354 fp->name = prop->name; |
|
1355 fp->format = prop->format; |
|
1356 fp->builtin = prop->builtin; |
|
1357 |
|
1358 switch ( prop->format ) |
|
1359 { |
|
1360 case BDF_ATOM: |
|
1361 fp->value.atom = 0; |
|
1362 if ( value != 0 && value[0] ) |
|
1363 { |
|
1364 if ( FT_STRDUP( fp->value.atom, value ) ) |
|
1365 goto Exit; |
|
1366 } |
|
1367 break; |
|
1368 |
|
1369 case BDF_INTEGER: |
|
1370 fp->value.l = _bdf_atol( value, 0, 10 ); |
|
1371 break; |
|
1372 |
|
1373 case BDF_CARDINAL: |
|
1374 fp->value.ul = _bdf_atoul( value, 0, 10 ); |
|
1375 break; |
|
1376 } |
|
1377 |
|
1378 /* If the property happens to be a comment, then it doesn't need */ |
|
1379 /* to be added to the internal hash table. */ |
|
1380 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) |
|
1381 { |
|
1382 /* Add the property to the font property table. */ |
|
1383 error = hash_insert( fp->name, |
|
1384 font->props_used, |
|
1385 (hashtable *)font->internal, |
|
1386 memory ); |
|
1387 if ( error ) |
|
1388 goto Exit; |
|
1389 } |
|
1390 |
|
1391 font->props_used++; |
|
1392 |
|
1393 /* Some special cases need to be handled here. The DEFAULT_CHAR */ |
|
1394 /* property needs to be located if it exists in the property list, the */ |
|
1395 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ |
|
1396 /* present, and the SPACING property should override the default */ |
|
1397 /* spacing. */ |
|
1398 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 ) |
|
1399 font->default_char = fp->value.l; |
|
1400 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 ) |
|
1401 font->font_ascent = fp->value.l; |
|
1402 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 ) |
|
1403 font->font_descent = fp->value.l; |
|
1404 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 ) |
|
1405 { |
|
1406 if ( !fp->value.atom ) |
|
1407 { |
|
1408 error = BDF_Err_Invalid_File_Format; |
|
1409 goto Exit; |
|
1410 } |
|
1411 |
|
1412 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) |
|
1413 font->spacing = BDF_PROPORTIONAL; |
|
1414 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) |
|
1415 font->spacing = BDF_MONOWIDTH; |
|
1416 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) |
|
1417 font->spacing = BDF_CHARCELL; |
|
1418 } |
|
1419 |
|
1420 Exit: |
|
1421 return error; |
|
1422 } |
|
1423 |
|
1424 |
|
1425 static const unsigned char nibble_mask[8] = |
|
1426 { |
|
1427 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE |
|
1428 }; |
|
1429 |
|
1430 |
|
1431 /* Actually parse the glyph info and bitmaps. */ |
|
1432 static FT_Error |
|
1433 _bdf_parse_glyphs( char* line, |
|
1434 unsigned long linelen, |
|
1435 unsigned long lineno, |
|
1436 void* call_data, |
|
1437 void* client_data ) |
|
1438 { |
|
1439 int c, mask_index; |
|
1440 char* s; |
|
1441 unsigned char* bp; |
|
1442 unsigned long i, slen, nibbles; |
|
1443 |
|
1444 _bdf_parse_t* p; |
|
1445 bdf_glyph_t* glyph; |
|
1446 bdf_font_t* font; |
|
1447 |
|
1448 FT_Memory memory; |
|
1449 FT_Error error = BDF_Err_Ok; |
|
1450 |
|
1451 FT_UNUSED( call_data ); |
|
1452 FT_UNUSED( lineno ); /* only used in debug mode */ |
|
1453 |
|
1454 |
|
1455 p = (_bdf_parse_t *)client_data; |
|
1456 |
|
1457 font = p->font; |
|
1458 memory = font->memory; |
|
1459 |
|
1460 /* Check for a comment. */ |
|
1461 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) |
|
1462 { |
|
1463 linelen -= 7; |
|
1464 |
|
1465 s = line + 7; |
|
1466 if ( *s != 0 ) |
|
1467 { |
|
1468 s++; |
|
1469 linelen--; |
|
1470 } |
|
1471 error = _bdf_add_comment( p->font, s, linelen ); |
|
1472 goto Exit; |
|
1473 } |
|
1474 |
|
1475 /* The very first thing expected is the number of glyphs. */ |
|
1476 if ( !( p->flags & _BDF_GLYPHS ) ) |
|
1477 { |
|
1478 if ( ft_memcmp( line, "CHARS", 5 ) != 0 ) |
|
1479 { |
|
1480 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); |
|
1481 error = BDF_Err_Missing_Chars_Field; |
|
1482 goto Exit; |
|
1483 } |
|
1484 |
|
1485 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1486 if ( error ) |
|
1487 goto Exit; |
|
1488 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 ); |
|
1489 |
|
1490 /* Make sure the number of glyphs is non-zero. */ |
|
1491 if ( p->cnt == 0 ) |
|
1492 font->glyphs_size = 64; |
|
1493 |
|
1494 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ |
|
1495 /* number of code points available in Unicode). */ |
|
1496 if ( p->cnt >= 1114112UL ) |
|
1497 { |
|
1498 error = BDF_Err_Invalid_Argument; |
|
1499 goto Exit; |
|
1500 } |
|
1501 |
|
1502 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) |
|
1503 goto Exit; |
|
1504 |
|
1505 p->flags |= _BDF_GLYPHS; |
|
1506 |
|
1507 goto Exit; |
|
1508 } |
|
1509 |
|
1510 /* Check for the ENDFONT field. */ |
|
1511 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 ) |
|
1512 { |
|
1513 /* Sort the glyphs by encoding. */ |
|
1514 ft_qsort( (char *)font->glyphs, |
|
1515 font->glyphs_used, |
|
1516 sizeof ( bdf_glyph_t ), |
|
1517 by_encoding ); |
|
1518 |
|
1519 p->flags &= ~_BDF_START; |
|
1520 |
|
1521 goto Exit; |
|
1522 } |
|
1523 |
|
1524 /* Check for the ENDCHAR field. */ |
|
1525 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 ) |
|
1526 { |
|
1527 p->glyph_enc = 0; |
|
1528 p->flags &= ~_BDF_GLYPH_BITS; |
|
1529 |
|
1530 goto Exit; |
|
1531 } |
|
1532 |
|
1533 /* Check to see whether a glyph is being scanned but should be */ |
|
1534 /* ignored because it is an unencoded glyph. */ |
|
1535 if ( ( p->flags & _BDF_GLYPH ) && |
|
1536 p->glyph_enc == -1 && |
|
1537 p->opts->keep_unencoded == 0 ) |
|
1538 goto Exit; |
|
1539 |
|
1540 /* Check for the STARTCHAR field. */ |
|
1541 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 ) |
|
1542 { |
|
1543 /* Set the character name in the parse info first until the */ |
|
1544 /* encoding can be checked for an unencoded character. */ |
|
1545 FT_FREE( p->glyph_name ); |
|
1546 |
|
1547 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1548 if ( error ) |
|
1549 goto Exit; |
|
1550 |
|
1551 _bdf_list_shift( &p->list, 1 ); |
|
1552 |
|
1553 s = _bdf_list_join( &p->list, ' ', &slen ); |
|
1554 |
|
1555 if ( !s ) |
|
1556 { |
|
1557 error = BDF_Err_Invalid_File_Format; |
|
1558 goto Exit; |
|
1559 } |
|
1560 |
|
1561 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) ) |
|
1562 goto Exit; |
|
1563 |
|
1564 FT_MEM_COPY( p->glyph_name, s, slen + 1 ); |
|
1565 |
|
1566 p->flags |= _BDF_GLYPH; |
|
1567 |
|
1568 goto Exit; |
|
1569 } |
|
1570 |
|
1571 /* Check for the ENCODING field. */ |
|
1572 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 ) |
|
1573 { |
|
1574 if ( !( p->flags & _BDF_GLYPH ) ) |
|
1575 { |
|
1576 /* Missing STARTCHAR field. */ |
|
1577 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); |
|
1578 error = BDF_Err_Missing_Startchar_Field; |
|
1579 goto Exit; |
|
1580 } |
|
1581 |
|
1582 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1583 if ( error ) |
|
1584 goto Exit; |
|
1585 |
|
1586 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 ); |
|
1587 |
|
1588 /* Check that the encoding is in the range [0,65536] because */ |
|
1589 /* otherwise p->have (a bitmap with static size) overflows. */ |
|
1590 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 ) |
|
1591 { |
|
1592 error = BDF_Err_Invalid_File_Format; |
|
1593 goto Exit; |
|
1594 } |
|
1595 |
|
1596 /* Check to see whether this encoding has already been encountered. */ |
|
1597 /* If it has then change it to unencoded so it gets added if */ |
|
1598 /* indicated. */ |
|
1599 if ( p->glyph_enc >= 0 ) |
|
1600 { |
|
1601 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) ) |
|
1602 { |
|
1603 /* Emit a message saying a glyph has been moved to the */ |
|
1604 /* unencoded area. */ |
|
1605 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12, |
|
1606 p->glyph_enc, p->glyph_name )); |
|
1607 p->glyph_enc = -1; |
|
1608 font->modified = 1; |
|
1609 } |
|
1610 else |
|
1611 _bdf_set_glyph_modified( p->have, p->glyph_enc ); |
|
1612 } |
|
1613 |
|
1614 if ( p->glyph_enc >= 0 ) |
|
1615 { |
|
1616 /* Make sure there are enough glyphs allocated in case the */ |
|
1617 /* number of characters happen to be wrong. */ |
|
1618 if ( font->glyphs_used == font->glyphs_size ) |
|
1619 { |
|
1620 if ( FT_RENEW_ARRAY( font->glyphs, |
|
1621 font->glyphs_size, |
|
1622 font->glyphs_size + 64 ) ) |
|
1623 goto Exit; |
|
1624 |
|
1625 font->glyphs_size += 64; |
|
1626 } |
|
1627 |
|
1628 glyph = font->glyphs + font->glyphs_used++; |
|
1629 glyph->name = p->glyph_name; |
|
1630 glyph->encoding = p->glyph_enc; |
|
1631 |
|
1632 /* Reset the initial glyph info. */ |
|
1633 p->glyph_name = 0; |
|
1634 } |
|
1635 else |
|
1636 { |
|
1637 /* Unencoded glyph. Check to see whether it should */ |
|
1638 /* be added or not. */ |
|
1639 if ( p->opts->keep_unencoded != 0 ) |
|
1640 { |
|
1641 /* Allocate the next unencoded glyph. */ |
|
1642 if ( font->unencoded_used == font->unencoded_size ) |
|
1643 { |
|
1644 if ( FT_RENEW_ARRAY( font->unencoded , |
|
1645 font->unencoded_size, |
|
1646 font->unencoded_size + 4 ) ) |
|
1647 goto Exit; |
|
1648 |
|
1649 font->unencoded_size += 4; |
|
1650 } |
|
1651 |
|
1652 glyph = font->unencoded + font->unencoded_used; |
|
1653 glyph->name = p->glyph_name; |
|
1654 glyph->encoding = font->unencoded_used++; |
|
1655 } |
|
1656 else |
|
1657 /* Free up the glyph name if the unencoded shouldn't be */ |
|
1658 /* kept. */ |
|
1659 FT_FREE( p->glyph_name ); |
|
1660 |
|
1661 p->glyph_name = 0; |
|
1662 } |
|
1663 |
|
1664 /* Clear the flags that might be added when width and height are */ |
|
1665 /* checked for consistency. */ |
|
1666 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK ); |
|
1667 |
|
1668 p->flags |= _BDF_ENCODING; |
|
1669 |
|
1670 goto Exit; |
|
1671 } |
|
1672 |
|
1673 /* Point at the glyph being constructed. */ |
|
1674 if ( p->glyph_enc == -1 ) |
|
1675 glyph = font->unencoded + ( font->unencoded_used - 1 ); |
|
1676 else |
|
1677 glyph = font->glyphs + ( font->glyphs_used - 1 ); |
|
1678 |
|
1679 /* Check to see whether a bitmap is being constructed. */ |
|
1680 if ( p->flags & _BDF_BITMAP ) |
|
1681 { |
|
1682 /* If there are more rows than are specified in the glyph metrics, */ |
|
1683 /* ignore the remaining lines. */ |
|
1684 if ( p->row >= (unsigned long)glyph->bbx.height ) |
|
1685 { |
|
1686 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) ) |
|
1687 { |
|
1688 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); |
|
1689 p->flags |= _BDF_GLYPH_HEIGHT_CHECK; |
|
1690 font->modified = 1; |
|
1691 } |
|
1692 |
|
1693 goto Exit; |
|
1694 } |
|
1695 |
|
1696 /* Only collect the number of nibbles indicated by the glyph */ |
|
1697 /* metrics. If there are more columns, they are simply ignored. */ |
|
1698 nibbles = glyph->bpr << 1; |
|
1699 bp = glyph->bitmap + p->row * glyph->bpr; |
|
1700 |
|
1701 for ( i = 0; i < nibbles; i++ ) |
|
1702 { |
|
1703 c = line[i]; |
|
1704 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); |
|
1705 if ( i + 1 < nibbles && ( i & 1 ) ) |
|
1706 *++bp = 0; |
|
1707 } |
|
1708 |
|
1709 /* Remove possible garbage at the right. */ |
|
1710 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; |
|
1711 if ( glyph->bbx.width ) |
|
1712 *bp &= nibble_mask[mask_index]; |
|
1713 |
|
1714 /* If any line has extra columns, indicate they have been removed. */ |
|
1715 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) && |
|
1716 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) |
|
1717 { |
|
1718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); |
|
1719 p->flags |= _BDF_GLYPH_WIDTH_CHECK; |
|
1720 font->modified = 1; |
|
1721 } |
|
1722 |
|
1723 p->row++; |
|
1724 goto Exit; |
|
1725 } |
|
1726 |
|
1727 /* Expect the SWIDTH (scalable width) field next. */ |
|
1728 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 ) |
|
1729 { |
|
1730 if ( !( p->flags & _BDF_ENCODING ) ) |
|
1731 { |
|
1732 /* Missing ENCODING field. */ |
|
1733 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); |
|
1734 error = BDF_Err_Missing_Encoding_Field; |
|
1735 goto Exit; |
|
1736 } |
|
1737 |
|
1738 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1739 if ( error ) |
|
1740 goto Exit; |
|
1741 |
|
1742 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); |
|
1743 p->flags |= _BDF_SWIDTH; |
|
1744 |
|
1745 goto Exit; |
|
1746 } |
|
1747 |
|
1748 /* Expect the DWIDTH (scalable width) field next. */ |
|
1749 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 ) |
|
1750 { |
|
1751 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1752 if ( error ) |
|
1753 goto Exit; |
|
1754 |
|
1755 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); |
|
1756 |
|
1757 if ( !( p->flags & _BDF_SWIDTH ) ) |
|
1758 { |
|
1759 /* Missing SWIDTH field. Emit an auto correction message and set */ |
|
1760 /* the scalable width from the device width. */ |
|
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); |
|
1762 |
|
1763 glyph->swidth = (unsigned short)FT_MulDiv( |
|
1764 glyph->dwidth, 72000L, |
|
1765 (FT_Long)( font->point_size * |
|
1766 font->resolution_x ) ); |
|
1767 } |
|
1768 |
|
1769 p->flags |= _BDF_DWIDTH; |
|
1770 goto Exit; |
|
1771 } |
|
1772 |
|
1773 /* Expect the BBX field next. */ |
|
1774 if ( ft_memcmp( line, "BBX", 3 ) == 0 ) |
|
1775 { |
|
1776 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1777 if ( error ) |
|
1778 goto Exit; |
|
1779 |
|
1780 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); |
|
1781 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); |
|
1782 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); |
|
1783 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); |
|
1784 |
|
1785 /* Generate the ascent and descent of the character. */ |
|
1786 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); |
|
1787 glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); |
|
1788 |
|
1789 /* Determine the overall font bounding box as the characters are */ |
|
1790 /* loaded so corrections can be done later if indicated. */ |
|
1791 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); |
|
1792 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); |
|
1793 |
|
1794 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); |
|
1795 |
|
1796 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); |
|
1797 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); |
|
1798 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); |
|
1799 |
|
1800 if ( !( p->flags & _BDF_DWIDTH ) ) |
|
1801 { |
|
1802 /* Missing DWIDTH field. Emit an auto correction message and set */ |
|
1803 /* the device width to the glyph width. */ |
|
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); |
|
1805 glyph->dwidth = glyph->bbx.width; |
|
1806 } |
|
1807 |
|
1808 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ |
|
1809 /* value if necessary. */ |
|
1810 if ( p->opts->correct_metrics != 0 ) |
|
1811 { |
|
1812 /* Determine the point size of the glyph. */ |
|
1813 unsigned short sw = (unsigned short)FT_MulDiv( |
|
1814 glyph->dwidth, 72000L, |
|
1815 (FT_Long)( font->point_size * |
|
1816 font->resolution_x ) ); |
|
1817 |
|
1818 |
|
1819 if ( sw != glyph->swidth ) |
|
1820 { |
|
1821 glyph->swidth = sw; |
|
1822 |
|
1823 if ( p->glyph_enc == -1 ) |
|
1824 _bdf_set_glyph_modified( font->umod, |
|
1825 font->unencoded_used - 1 ); |
|
1826 else |
|
1827 _bdf_set_glyph_modified( font->nmod, glyph->encoding ); |
|
1828 |
|
1829 p->flags |= _BDF_SWIDTH_ADJ; |
|
1830 font->modified = 1; |
|
1831 } |
|
1832 } |
|
1833 |
|
1834 p->flags |= _BDF_BBX; |
|
1835 goto Exit; |
|
1836 } |
|
1837 |
|
1838 /* And finally, gather up the bitmap. */ |
|
1839 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 ) |
|
1840 { |
|
1841 unsigned long bitmap_size; |
|
1842 |
|
1843 |
|
1844 if ( !( p->flags & _BDF_BBX ) ) |
|
1845 { |
|
1846 /* Missing BBX field. */ |
|
1847 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); |
|
1848 error = BDF_Err_Missing_Bbx_Field; |
|
1849 goto Exit; |
|
1850 } |
|
1851 |
|
1852 /* Allocate enough space for the bitmap. */ |
|
1853 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; |
|
1854 |
|
1855 bitmap_size = glyph->bpr * glyph->bbx.height; |
|
1856 if ( bitmap_size > 0xFFFFU ) |
|
1857 { |
|
1858 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); |
|
1859 error = BDF_Err_Bbx_Too_Big; |
|
1860 goto Exit; |
|
1861 } |
|
1862 else |
|
1863 glyph->bytes = (unsigned short)bitmap_size; |
|
1864 |
|
1865 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) |
|
1866 goto Exit; |
|
1867 |
|
1868 p->row = 0; |
|
1869 p->flags |= _BDF_BITMAP; |
|
1870 |
|
1871 goto Exit; |
|
1872 } |
|
1873 |
|
1874 error = BDF_Err_Invalid_File_Format; |
|
1875 |
|
1876 Exit: |
|
1877 if ( error && ( p->flags & _BDF_GLYPH ) ) |
|
1878 FT_FREE( p->glyph_name ); |
|
1879 |
|
1880 return error; |
|
1881 } |
|
1882 |
|
1883 |
|
1884 /* Load the font properties. */ |
|
1885 static FT_Error |
|
1886 _bdf_parse_properties( char* line, |
|
1887 unsigned long linelen, |
|
1888 unsigned long lineno, |
|
1889 void* call_data, |
|
1890 void* client_data ) |
|
1891 { |
|
1892 unsigned long vlen; |
|
1893 _bdf_line_func_t* next; |
|
1894 _bdf_parse_t* p; |
|
1895 char* name; |
|
1896 char* value; |
|
1897 char nbuf[128]; |
|
1898 FT_Error error = BDF_Err_Ok; |
|
1899 |
|
1900 FT_UNUSED( lineno ); |
|
1901 |
|
1902 |
|
1903 next = (_bdf_line_func_t *)call_data; |
|
1904 p = (_bdf_parse_t *) client_data; |
|
1905 |
|
1906 /* Check for the end of the properties. */ |
|
1907 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 ) |
|
1908 { |
|
1909 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ |
|
1910 /* encountered yet, then make sure they are added as properties and */ |
|
1911 /* make sure they are set from the font bounding box info. */ |
|
1912 /* */ |
|
1913 /* This is *always* done regardless of the options, because X11 */ |
|
1914 /* requires these two fields to compile fonts. */ |
|
1915 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) |
|
1916 { |
|
1917 p->font->font_ascent = p->font->bbx.ascent; |
|
1918 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); |
|
1919 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf ); |
|
1920 if ( error ) |
|
1921 goto Exit; |
|
1922 |
|
1923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); |
|
1924 p->font->modified = 1; |
|
1925 } |
|
1926 |
|
1927 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) |
|
1928 { |
|
1929 p->font->font_descent = p->font->bbx.descent; |
|
1930 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); |
|
1931 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf ); |
|
1932 if ( error ) |
|
1933 goto Exit; |
|
1934 |
|
1935 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); |
|
1936 p->font->modified = 1; |
|
1937 } |
|
1938 |
|
1939 p->flags &= ~_BDF_PROPS; |
|
1940 *next = _bdf_parse_glyphs; |
|
1941 |
|
1942 goto Exit; |
|
1943 } |
|
1944 |
|
1945 /* Ignore the _XFREE86_GLYPH_RANGES properties. */ |
|
1946 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) |
|
1947 goto Exit; |
|
1948 |
|
1949 /* Handle COMMENT fields and properties in a special way to preserve */ |
|
1950 /* the spacing. */ |
|
1951 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) |
|
1952 { |
|
1953 name = value = line; |
|
1954 value += 7; |
|
1955 if ( *value ) |
|
1956 *value++ = 0; |
|
1957 error = _bdf_add_property( p->font, name, value ); |
|
1958 if ( error ) |
|
1959 goto Exit; |
|
1960 } |
|
1961 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) |
|
1962 { |
|
1963 error = _bdf_add_property( p->font, name, value ); |
|
1964 if ( error ) |
|
1965 goto Exit; |
|
1966 } |
|
1967 else |
|
1968 { |
|
1969 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
1970 if ( error ) |
|
1971 goto Exit; |
|
1972 name = p->list.field[0]; |
|
1973 |
|
1974 _bdf_list_shift( &p->list, 1 ); |
|
1975 value = _bdf_list_join( &p->list, ' ', &vlen ); |
|
1976 |
|
1977 error = _bdf_add_property( p->font, name, value ); |
|
1978 if ( error ) |
|
1979 goto Exit; |
|
1980 } |
|
1981 |
|
1982 Exit: |
|
1983 return error; |
|
1984 } |
|
1985 |
|
1986 |
|
1987 /* Load the font header. */ |
|
1988 static FT_Error |
|
1989 _bdf_parse_start( char* line, |
|
1990 unsigned long linelen, |
|
1991 unsigned long lineno, |
|
1992 void* call_data, |
|
1993 void* client_data ) |
|
1994 { |
|
1995 unsigned long slen; |
|
1996 _bdf_line_func_t* next; |
|
1997 _bdf_parse_t* p; |
|
1998 bdf_font_t* font; |
|
1999 char *s; |
|
2000 |
|
2001 FT_Memory memory = NULL; |
|
2002 FT_Error error = BDF_Err_Ok; |
|
2003 |
|
2004 FT_UNUSED( lineno ); /* only used in debug mode */ |
|
2005 |
|
2006 |
|
2007 next = (_bdf_line_func_t *)call_data; |
|
2008 p = (_bdf_parse_t *) client_data; |
|
2009 |
|
2010 if ( p->font ) |
|
2011 memory = p->font->memory; |
|
2012 |
|
2013 /* Check for a comment. This is done to handle those fonts that have */ |
|
2014 /* comments before the STARTFONT line for some reason. */ |
|
2015 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) |
|
2016 { |
|
2017 if ( p->opts->keep_comments != 0 && p->font != 0 ) |
|
2018 { |
|
2019 linelen -= 7; |
|
2020 |
|
2021 s = line + 7; |
|
2022 if ( *s != 0 ) |
|
2023 { |
|
2024 s++; |
|
2025 linelen--; |
|
2026 } |
|
2027 |
|
2028 error = _bdf_add_comment( p->font, s, linelen ); |
|
2029 if ( error ) |
|
2030 goto Exit; |
|
2031 /* here font is not defined! */ |
|
2032 } |
|
2033 |
|
2034 goto Exit; |
|
2035 } |
|
2036 |
|
2037 if ( !( p->flags & _BDF_START ) ) |
|
2038 { |
|
2039 memory = p->memory; |
|
2040 |
|
2041 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 ) |
|
2042 { |
|
2043 /* No STARTFONT field is a good indication of a problem. */ |
|
2044 error = BDF_Err_Missing_Startfont_Field; |
|
2045 goto Exit; |
|
2046 } |
|
2047 |
|
2048 p->flags = _BDF_START; |
|
2049 font = p->font = 0; |
|
2050 |
|
2051 if ( FT_NEW( font ) ) |
|
2052 goto Exit; |
|
2053 p->font = font; |
|
2054 |
|
2055 font->memory = p->memory; |
|
2056 p->memory = 0; |
|
2057 |
|
2058 { /* setup */ |
|
2059 size_t i; |
|
2060 bdf_property_t* prop; |
|
2061 |
|
2062 |
|
2063 error = hash_init( &(font->proptbl), memory ); |
|
2064 if ( error ) |
|
2065 goto Exit; |
|
2066 for ( i = 0, prop = (bdf_property_t*)_bdf_properties; |
|
2067 i < _num_bdf_properties; i++, prop++ ) |
|
2068 { |
|
2069 error = hash_insert( prop->name, i, |
|
2070 &(font->proptbl), memory ); |
|
2071 if ( error ) |
|
2072 goto Exit; |
|
2073 } |
|
2074 } |
|
2075 |
|
2076 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) ) |
|
2077 goto Exit; |
|
2078 error = hash_init( (hashtable *)p->font->internal,memory ); |
|
2079 if ( error ) |
|
2080 goto Exit; |
|
2081 p->font->spacing = p->opts->font_spacing; |
|
2082 p->font->default_char = -1; |
|
2083 |
|
2084 goto Exit; |
|
2085 } |
|
2086 |
|
2087 /* Check for the start of the properties. */ |
|
2088 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 ) |
|
2089 { |
|
2090 if ( !( p->flags & _BDF_FONT_BBX ) ) |
|
2091 { |
|
2092 /* Missing the FONTBOUNDINGBOX field. */ |
|
2093 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); |
|
2094 error = BDF_Err_Missing_Fontboundingbox_Field; |
|
2095 goto Exit; |
|
2096 } |
|
2097 |
|
2098 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
2099 if ( error ) |
|
2100 goto Exit; |
|
2101 /* at this point, `p->font' can't be NULL */ |
|
2102 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 ); |
|
2103 |
|
2104 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) |
|
2105 goto Exit; |
|
2106 |
|
2107 p->flags |= _BDF_PROPS; |
|
2108 *next = _bdf_parse_properties; |
|
2109 |
|
2110 goto Exit; |
|
2111 } |
|
2112 |
|
2113 /* Check for the FONTBOUNDINGBOX field. */ |
|
2114 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) |
|
2115 { |
|
2116 if ( !( p->flags & _BDF_SIZE ) ) |
|
2117 { |
|
2118 /* Missing the SIZE field. */ |
|
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); |
|
2120 error = BDF_Err_Missing_Size_Field; |
|
2121 goto Exit; |
|
2122 } |
|
2123 |
|
2124 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
2125 if ( error ) |
|
2126 goto Exit; |
|
2127 |
|
2128 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); |
|
2129 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); |
|
2130 |
|
2131 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); |
|
2132 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); |
|
2133 |
|
2134 p->font->bbx.ascent = (short)( p->font->bbx.height + |
|
2135 p->font->bbx.y_offset ); |
|
2136 |
|
2137 p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); |
|
2138 |
|
2139 p->flags |= _BDF_FONT_BBX; |
|
2140 |
|
2141 goto Exit; |
|
2142 } |
|
2143 |
|
2144 /* The next thing to check for is the FONT field. */ |
|
2145 if ( ft_memcmp( line, "FONT", 4 ) == 0 ) |
|
2146 { |
|
2147 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
2148 if ( error ) |
|
2149 goto Exit; |
|
2150 _bdf_list_shift( &p->list, 1 ); |
|
2151 |
|
2152 s = _bdf_list_join( &p->list, ' ', &slen ); |
|
2153 |
|
2154 if ( !s ) |
|
2155 { |
|
2156 error = BDF_Err_Invalid_File_Format; |
|
2157 goto Exit; |
|
2158 } |
|
2159 |
|
2160 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ |
|
2161 FT_FREE( p->font->name ); |
|
2162 |
|
2163 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) |
|
2164 goto Exit; |
|
2165 FT_MEM_COPY( p->font->name, s, slen + 1 ); |
|
2166 |
|
2167 /* If the font name is an XLFD name, set the spacing to the one in */ |
|
2168 /* the font name. If there is no spacing fall back on the default. */ |
|
2169 error = _bdf_set_default_spacing( p->font, p->opts ); |
|
2170 if ( error ) |
|
2171 goto Exit; |
|
2172 |
|
2173 p->flags |= _BDF_FONT_NAME; |
|
2174 |
|
2175 goto Exit; |
|
2176 } |
|
2177 |
|
2178 /* Check for the SIZE field. */ |
|
2179 if ( ft_memcmp( line, "SIZE", 4 ) == 0 ) |
|
2180 { |
|
2181 if ( !( p->flags & _BDF_FONT_NAME ) ) |
|
2182 { |
|
2183 /* Missing the FONT field. */ |
|
2184 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); |
|
2185 error = BDF_Err_Missing_Font_Field; |
|
2186 goto Exit; |
|
2187 } |
|
2188 |
|
2189 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); |
|
2190 if ( error ) |
|
2191 goto Exit; |
|
2192 |
|
2193 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 ); |
|
2194 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 ); |
|
2195 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 ); |
|
2196 |
|
2197 /* Check for the bits per pixel field. */ |
|
2198 if ( p->list.used == 5 ) |
|
2199 { |
|
2200 unsigned short bitcount, i, shift; |
|
2201 |
|
2202 |
|
2203 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 ); |
|
2204 |
|
2205 /* Only values 1, 2, 4, 8 are allowed. */ |
|
2206 shift = p->font->bpp; |
|
2207 bitcount = 0; |
|
2208 for ( i = 0; shift > 0; i++ ) |
|
2209 { |
|
2210 if ( shift & 1 ) |
|
2211 bitcount = i; |
|
2212 shift >>= 1; |
|
2213 } |
|
2214 |
|
2215 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) ); |
|
2216 |
|
2217 if ( p->font->bpp > shift || p->font->bpp != shift ) |
|
2218 { |
|
2219 /* select next higher value */ |
|
2220 p->font->bpp = (unsigned short)( shift << 1 ); |
|
2221 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); |
|
2222 } |
|
2223 } |
|
2224 else |
|
2225 p->font->bpp = 1; |
|
2226 |
|
2227 p->flags |= _BDF_SIZE; |
|
2228 |
|
2229 goto Exit; |
|
2230 } |
|
2231 |
|
2232 /* Check for the CHARS field -- font properties are optional */ |
|
2233 if ( ft_memcmp( line, "CHARS", 5 ) == 0 ) |
|
2234 { |
|
2235 char nbuf[128]; |
|
2236 |
|
2237 |
|
2238 if ( !( p->flags & _BDF_FONT_BBX ) ) |
|
2239 { |
|
2240 /* Missing the FONTBOUNDINGBOX field. */ |
|
2241 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); |
|
2242 error = BDF_Err_Missing_Fontboundingbox_Field; |
|
2243 goto Exit; |
|
2244 } |
|
2245 |
|
2246 /* Add the two standard X11 properties which are required */ |
|
2247 /* for compiling fonts. */ |
|
2248 p->font->font_ascent = p->font->bbx.ascent; |
|
2249 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); |
|
2250 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf ); |
|
2251 if ( error ) |
|
2252 goto Exit; |
|
2253 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); |
|
2254 |
|
2255 p->font->font_descent = p->font->bbx.descent; |
|
2256 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); |
|
2257 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf ); |
|
2258 if ( error ) |
|
2259 goto Exit; |
|
2260 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); |
|
2261 |
|
2262 p->font->modified = 1; |
|
2263 |
|
2264 *next = _bdf_parse_glyphs; |
|
2265 |
|
2266 /* A special return value. */ |
|
2267 error = -1; |
|
2268 goto Exit; |
|
2269 } |
|
2270 |
|
2271 error = BDF_Err_Invalid_File_Format; |
|
2272 |
|
2273 Exit: |
|
2274 return error; |
|
2275 } |
|
2276 |
|
2277 |
|
2278 /*************************************************************************/ |
|
2279 /* */ |
|
2280 /* API. */ |
|
2281 /* */ |
|
2282 /*************************************************************************/ |
|
2283 |
|
2284 |
|
2285 FT_LOCAL_DEF( FT_Error ) |
|
2286 bdf_load_font( FT_Stream stream, |
|
2287 FT_Memory extmemory, |
|
2288 bdf_options_t* opts, |
|
2289 bdf_font_t* *font ) |
|
2290 { |
|
2291 unsigned long lineno = 0; /* make compiler happy */ |
|
2292 _bdf_parse_t *p = NULL; |
|
2293 |
|
2294 FT_Memory memory = extmemory; |
|
2295 FT_Error error = BDF_Err_Ok; |
|
2296 |
|
2297 |
|
2298 if ( FT_NEW( p ) ) |
|
2299 goto Exit; |
|
2300 |
|
2301 memory = NULL; |
|
2302 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); |
|
2303 p->minlb = 32767; |
|
2304 p->memory = extmemory; /* only during font creation */ |
|
2305 |
|
2306 _bdf_list_init( &p->list, extmemory ); |
|
2307 |
|
2308 error = _bdf_readstream( stream, _bdf_parse_start, |
|
2309 (void *)p, &lineno ); |
|
2310 if ( error ) |
|
2311 goto Fail; |
|
2312 |
|
2313 if ( p->font != 0 ) |
|
2314 { |
|
2315 /* If the font is not proportional, set the font's monowidth */ |
|
2316 /* field to the width of the font bounding box. */ |
|
2317 memory = p->font->memory; |
|
2318 |
|
2319 if ( p->font->spacing != BDF_PROPORTIONAL ) |
|
2320 p->font->monowidth = p->font->bbx.width; |
|
2321 |
|
2322 /* If the number of glyphs loaded is not that of the original count, */ |
|
2323 /* indicate the difference. */ |
|
2324 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) |
|
2325 { |
|
2326 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, |
|
2327 p->font->glyphs_used + p->font->unencoded_used )); |
|
2328 p->font->modified = 1; |
|
2329 } |
|
2330 |
|
2331 /* Once the font has been loaded, adjust the overall font metrics if */ |
|
2332 /* necessary. */ |
|
2333 if ( p->opts->correct_metrics != 0 && |
|
2334 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) |
|
2335 { |
|
2336 if ( p->maxrb - p->minlb != p->font->bbx.width ) |
|
2337 { |
|
2338 FT_TRACE2(( "bdf_load_font: " ACMSG3, |
|
2339 p->font->bbx.width, p->maxrb - p->minlb )); |
|
2340 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); |
|
2341 p->font->modified = 1; |
|
2342 } |
|
2343 |
|
2344 if ( p->font->bbx.x_offset != p->minlb ) |
|
2345 { |
|
2346 FT_TRACE2(( "bdf_load_font: " ACMSG4, |
|
2347 p->font->bbx.x_offset, p->minlb )); |
|
2348 p->font->bbx.x_offset = p->minlb; |
|
2349 p->font->modified = 1; |
|
2350 } |
|
2351 |
|
2352 if ( p->font->bbx.ascent != p->maxas ) |
|
2353 { |
|
2354 FT_TRACE2(( "bdf_load_font: " ACMSG5, |
|
2355 p->font->bbx.ascent, p->maxas )); |
|
2356 p->font->bbx.ascent = p->maxas; |
|
2357 p->font->modified = 1; |
|
2358 } |
|
2359 |
|
2360 if ( p->font->bbx.descent != p->maxds ) |
|
2361 { |
|
2362 FT_TRACE2(( "bdf_load_font: " ACMSG6, |
|
2363 p->font->bbx.descent, p->maxds )); |
|
2364 p->font->bbx.descent = p->maxds; |
|
2365 p->font->bbx.y_offset = (short)( -p->maxds ); |
|
2366 p->font->modified = 1; |
|
2367 } |
|
2368 |
|
2369 if ( p->maxas + p->maxds != p->font->bbx.height ) |
|
2370 { |
|
2371 FT_TRACE2(( "bdf_load_font: " ACMSG7, |
|
2372 p->font->bbx.height, p->maxas + p->maxds )); |
|
2373 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); |
|
2374 } |
|
2375 |
|
2376 if ( p->flags & _BDF_SWIDTH_ADJ ) |
|
2377 FT_TRACE2(( "bdf_load_font: " ACMSG8 )); |
|
2378 } |
|
2379 } |
|
2380 |
|
2381 if ( p->flags & _BDF_START ) |
|
2382 { |
|
2383 { |
|
2384 /* The ENDFONT field was never reached or did not exist. */ |
|
2385 if ( !( p->flags & _BDF_GLYPHS ) ) |
|
2386 { |
|
2387 /* Error happened while parsing header. */ |
|
2388 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); |
|
2389 error = BDF_Err_Corrupted_Font_Header; |
|
2390 goto Exit; |
|
2391 } |
|
2392 else |
|
2393 { |
|
2394 /* Error happened when parsing glyphs. */ |
|
2395 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); |
|
2396 error = BDF_Err_Corrupted_Font_Glyphs; |
|
2397 goto Exit; |
|
2398 } |
|
2399 } |
|
2400 } |
|
2401 |
|
2402 if ( p->font != 0 ) |
|
2403 { |
|
2404 /* Make sure the comments are NULL terminated if they exist. */ |
|
2405 memory = p->font->memory; |
|
2406 |
|
2407 if ( p->font->comments_len > 0 ) |
|
2408 { |
|
2409 if ( FT_RENEW_ARRAY( p->font->comments, |
|
2410 p->font->comments_len, |
|
2411 p->font->comments_len + 1 ) ) |
|
2412 goto Fail; |
|
2413 |
|
2414 p->font->comments[p->font->comments_len] = 0; |
|
2415 } |
|
2416 } |
|
2417 else if ( error == BDF_Err_Ok ) |
|
2418 error = BDF_Err_Invalid_File_Format; |
|
2419 |
|
2420 *font = p->font; |
|
2421 |
|
2422 Exit: |
|
2423 if ( p ) |
|
2424 { |
|
2425 _bdf_list_done( &p->list ); |
|
2426 |
|
2427 memory = extmemory; |
|
2428 |
|
2429 FT_FREE( p ); |
|
2430 } |
|
2431 |
|
2432 return error; |
|
2433 |
|
2434 Fail: |
|
2435 bdf_free_font( p->font ); |
|
2436 |
|
2437 memory = extmemory; |
|
2438 |
|
2439 FT_FREE( p->font ); |
|
2440 |
|
2441 goto Exit; |
|
2442 } |
|
2443 |
|
2444 |
|
2445 FT_LOCAL_DEF( void ) |
|
2446 bdf_free_font( bdf_font_t* font ) |
|
2447 { |
|
2448 bdf_property_t* prop; |
|
2449 unsigned long i; |
|
2450 bdf_glyph_t* glyphs; |
|
2451 FT_Memory memory; |
|
2452 |
|
2453 |
|
2454 if ( font == 0 ) |
|
2455 return; |
|
2456 |
|
2457 memory = font->memory; |
|
2458 |
|
2459 FT_FREE( font->name ); |
|
2460 |
|
2461 /* Free up the internal hash table of property names. */ |
|
2462 if ( font->internal ) |
|
2463 { |
|
2464 hash_free( (hashtable *)font->internal, memory ); |
|
2465 FT_FREE( font->internal ); |
|
2466 } |
|
2467 |
|
2468 /* Free up the comment info. */ |
|
2469 FT_FREE( font->comments ); |
|
2470 |
|
2471 /* Free up the properties. */ |
|
2472 for ( i = 0; i < font->props_size; i++ ) |
|
2473 { |
|
2474 if ( font->props[i].format == BDF_ATOM ) |
|
2475 FT_FREE( font->props[i].value.atom ); |
|
2476 } |
|
2477 |
|
2478 FT_FREE( font->props ); |
|
2479 |
|
2480 /* Free up the character info. */ |
|
2481 for ( i = 0, glyphs = font->glyphs; |
|
2482 i < font->glyphs_used; i++, glyphs++ ) |
|
2483 { |
|
2484 FT_FREE( glyphs->name ); |
|
2485 FT_FREE( glyphs->bitmap ); |
|
2486 } |
|
2487 |
|
2488 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; |
|
2489 i++, glyphs++ ) |
|
2490 { |
|
2491 FT_FREE( glyphs->name ); |
|
2492 FT_FREE( glyphs->bitmap ); |
|
2493 } |
|
2494 |
|
2495 FT_FREE( font->glyphs ); |
|
2496 FT_FREE( font->unencoded ); |
|
2497 |
|
2498 /* Free up the overflow storage if it was used. */ |
|
2499 for ( i = 0, glyphs = font->overflow.glyphs; |
|
2500 i < font->overflow.glyphs_used; i++, glyphs++ ) |
|
2501 { |
|
2502 FT_FREE( glyphs->name ); |
|
2503 FT_FREE( glyphs->bitmap ); |
|
2504 } |
|
2505 |
|
2506 FT_FREE( font->overflow.glyphs ); |
|
2507 |
|
2508 /* bdf_cleanup */ |
|
2509 hash_free( &(font->proptbl), memory ); |
|
2510 |
|
2511 /* Free up the user defined properties. */ |
|
2512 for ( prop = font->user_props, i = 0; |
|
2513 i < font->nuser_props; i++, prop++ ) |
|
2514 { |
|
2515 FT_FREE( prop->name ); |
|
2516 if ( prop->format == BDF_ATOM ) |
|
2517 FT_FREE( prop->value.atom ); |
|
2518 } |
|
2519 |
|
2520 FT_FREE( font->user_props ); |
|
2521 |
|
2522 /* FREE( font ); */ /* XXX Fixme */ |
|
2523 } |
|
2524 |
|
2525 |
|
2526 FT_LOCAL_DEF( bdf_property_t * ) |
|
2527 bdf_get_font_property( bdf_font_t* font, |
|
2528 const char* name ) |
|
2529 { |
|
2530 hashnode hn; |
|
2531 |
|
2532 |
|
2533 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) |
|
2534 return 0; |
|
2535 |
|
2536 hn = hash_lookup( name, (hashtable *)font->internal ); |
|
2537 |
|
2538 return hn ? ( font->props + hn->data ) : 0; |
|
2539 } |
|
2540 |
|
2541 |
|
2542 /* END */ |
|