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