pcfread.c revision 8eb0353fec1494ab7d9fe9bb91a5954449ab30c1
1/*  pcfread.c
2
3    FreeType font driver for pcf fonts
4
5  Copyright 2000 by
6  Francesco Zappa Nardelli
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24THE SOFTWARE.
25*/
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 "pcf.h"
35#include "pcfdriver.h"
36
37#include "pcferror.h"
38
39#include <string.h>     /* strlen(), strcpy() */
40
41  /*************************************************************************/
42  /*                                                                       */
43  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
44  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
45  /* messages during execution.                                            */
46  /*                                                                       */
47#undef  FT_COMPONENT
48#define FT_COMPONENT  trace_pcfread
49
50
51#if defined( FT_DEBUG_LEVEL_TRACE )
52  static char*  tableNames[] =
53  {
54    "prop", "accl", "mtrcs", "bmps", "imtrcs",
55    "enc", "swidth", "names", "accel"
56  };
57#endif
58
59
60  static
61  const FT_Frame_Field  pcf_toc_header[] =
62  {
63#undef  FT_STRUCTURE
64#define FT_STRUCTURE  PCF_TocRec
65
66    FT_FRAME_START( 8 ),
67      FT_FRAME_ULONG_LE( version ),
68      FT_FRAME_ULONG_LE( count ),
69    FT_FRAME_END
70  };
71
72
73  static
74  const FT_Frame_Field  pcf_table_header[] =
75  {
76#undef  FT_STRUCTURE
77#define FT_STRUCTURE  PCF_TableRec
78
79    FT_FRAME_START( 16  ),
80      FT_FRAME_ULONG_LE( type ),
81      FT_FRAME_ULONG_LE( format ),
82      FT_FRAME_ULONG_LE( size ),
83      FT_FRAME_ULONG_LE( offset ),
84    FT_FRAME_END
85  };
86
87
88  static
89  FT_Error pcf_read_TOC( FT_Stream  stream,
90                         PCF_Face   face )
91  {
92    FT_Error   error;
93    PCF_Toc    toc = &face->toc;
94    PCF_Table  tables;
95
96    FT_Memory     memory = FT_FACE(face)->memory;
97    unsigned int  i;
98
99
100    if ( FILE_Seek ( 0 )                   ||
101         READ_Fields ( pcf_toc_header, toc ) )
102      return PCF_Err_Cannot_Open_Resource;
103
104    if ( toc->version != PCF_FILE_VERSION )
105      return PCF_Err_Invalid_File_Format;
106
107    if ( ALLOC( face->toc.tables, toc->count * sizeof ( PCF_TableRec ) ) )
108      return PCF_Err_Out_Of_Memory;
109
110    tables = face->toc.tables;
111    for ( i = 0; i < toc->count; i++ )
112    {
113      if ( READ_Fields( pcf_table_header, tables ) )
114        goto Exit;
115      tables++;
116    }
117
118#if defined( FT_DEBUG_LEVEL_TRACE )
119
120    {
121      unsigned int  i,j;
122      char*         name = "?";
123
124
125      FT_TRACE4(( "Tables count: %ld\n", face->toc.count ));
126      tables = face->toc.tables;
127      for ( i = 0; i < toc->count; i++ )
128      {
129        for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ )
130          if ( tables[i].type == (unsigned int)( 1 << j ) )
131            name=tableNames[j];
132        FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX "
133                    "size=0x%06lX (%8ld) offset=0x%04lX\n",
134                    i, name,
135                    tables[i].format,
136                    tables[i].size, tables[i].size,
137                    tables[i].offset ));
138      }
139    }
140
141#endif
142
143    return PCF_Err_Ok;
144
145  Exit:
146    FREE( face->toc.tables );
147    return error;
148  }
149
150
151  static
152  const FT_Frame_Field  pcf_metric_header[] =
153  {
154#undef  FT_STRUCTURE
155#define FT_STRUCTURE  PCF_MetricRec
156
157    FT_FRAME_START( 12 ),
158      FT_FRAME_SHORT_LE( leftSideBearing ),
159      FT_FRAME_SHORT_LE( rightSideBearing ),
160      FT_FRAME_SHORT_LE( characterWidth ),
161      FT_FRAME_SHORT_LE( ascent ),
162      FT_FRAME_SHORT_LE( descent ),
163      FT_FRAME_SHORT_LE( attributes ),
164    FT_FRAME_END
165  };
166
167
168  static
169  const FT_Frame_Field  pcf_metric_msb_header[] =
170  {
171#undef  FT_STRUCTURE
172#define FT_STRUCTURE  PCF_MetricRec
173
174    FT_FRAME_START( 12 ),
175      FT_FRAME_SHORT( leftSideBearing ),
176      FT_FRAME_SHORT( rightSideBearing ),
177      FT_FRAME_SHORT( characterWidth ),
178      FT_FRAME_SHORT( ascent ),
179      FT_FRAME_SHORT( descent ),
180      FT_FRAME_SHORT( attributes ),
181    FT_FRAME_END
182  };
183
184
185  static
186  const FT_Frame_Field  pcf_compressed_metric_header[] =
187  {
188#undef  FT_STRUCTURE
189#define FT_STRUCTURE  PCF_Compressed_MetricRec
190
191    FT_FRAME_START( 5 ),
192      FT_FRAME_BYTE( leftSideBearing ),
193      FT_FRAME_BYTE( rightSideBearing ),
194      FT_FRAME_BYTE( characterWidth ),
195      FT_FRAME_BYTE( ascent ),
196      FT_FRAME_BYTE( descent ),
197    FT_FRAME_END
198  };
199
200
201  static
202  FT_Error  pcf_parse_metric( FT_Stream              stream,
203                              const FT_Frame_Field*  header,
204                              PCF_Metric             metric )
205  {
206    FT_Error  error = PCF_Err_Ok;
207
208
209    if ( READ_Fields( header, metric ) )
210      return error;
211
212    return PCF_Err_Ok;
213  }
214
215
216  static
217  FT_Error  pcf_parse_compressed_metric( FT_Stream   stream,
218                                         PCF_Metric  metric )
219  {
220    PCF_Compressed_MetricRec  compr_metric;
221    FT_Error                  error = PCF_Err_Ok;
222
223
224    if ( READ_Fields( pcf_compressed_metric_header, &compr_metric ) )
225      return error;
226
227    metric->leftSideBearing =
228      (FT_Short)( compr_metric.leftSideBearing - 0x80 );
229    metric->rightSideBearing =
230      (FT_Short)( compr_metric.rightSideBearing - 0x80 );
231    metric->characterWidth =
232      (FT_Short)( compr_metric.characterWidth - 0x80 );
233    metric->ascent =
234      (FT_Short)( compr_metric.ascent - 0x80 );
235    metric->descent =
236      (FT_Short)( compr_metric.descent - 0x80 );
237    metric->attributes = 0;
238
239    return PCF_Err_Ok;
240  }
241
242
243  static
244  FT_Error  pcf_get_metric( FT_Stream   stream,
245                            FT_ULong    format,
246                            PCF_Metric  metric )
247  {
248    FT_Error error = PCF_Err_Ok;
249
250
251    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
252    {
253      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
254        error = pcf_parse_metric( stream, pcf_metric_msb_header, metric );
255      else
256        error = pcf_parse_metric( stream, pcf_metric_header, metric );
257    }
258    else
259      error = pcf_parse_compressed_metric( stream, metric );
260
261    return error;
262  }
263
264
265  static
266  FT_Error  pcfSeekToType( FT_Stream  stream,
267                           PCF_Table  tables,
268                           int        ntables,
269                           FT_ULong   type,
270                           FT_ULong*  formatp,
271                           FT_ULong*  sizep )
272  {
273    FT_Error error;
274    int      i;
275
276
277    for ( i = 0; i < ntables; i++ )
278      if ( tables[i].type == type )
279      {
280        if ( stream->pos > tables[i].offset )
281          return PCF_Err_Invalid_Stream_Skip;
282        if ( FILE_Skip( tables[i].offset - stream->pos ) )
283          return PCF_Err_Invalid_Stream_Skip;
284        *sizep   = tables[i].size;  /* unused - to be removed */
285        *formatp = tables[i].format;
286        return PCF_Err_Ok;
287      }
288
289    return PCF_Err_Invalid_File_Format;
290  }
291
292
293  static
294  FT_Bool  pcfHasType( PCF_Table  tables,
295                       int        ntables,
296                       FT_ULong   type )
297  {
298    int i;
299
300
301    for ( i = 0; i < ntables; i++ )
302      if ( tables[i].type == type )
303        return TRUE;
304
305    return FALSE;
306  }
307
308
309  static
310  const FT_Frame_Field  pcf_property_header[] =
311  {
312#undef  FT_STRUCTURE
313#define FT_STRUCTURE  PCF_ParsePropertyRec
314
315    FT_FRAME_START( 9 ),
316      FT_FRAME_LONG_LE( name ),
317      FT_FRAME_BYTE   ( isString ),
318      FT_FRAME_LONG_LE( value ),
319    FT_FRAME_END
320  };
321
322
323  static
324  const FT_Frame_Field  pcf_property_msb_header[] =
325  {
326#undef  FT_STRUCTURE
327#define FT_STRUCTURE  PCF_ParsePropertyRec
328
329    FT_FRAME_START( 9 ),
330      FT_FRAME_LONG( name ),
331      FT_FRAME_BYTE( isString ),
332      FT_FRAME_LONG( value ),
333    FT_FRAME_END
334  };
335
336
337  static
338  PCF_Property  find_property( PCF_Face          face,
339                               const FT_String*  prop )
340  {
341    PCF_Property  properties = face->properties;
342    FT_Bool       found      = 0;
343    int           i;
344
345
346    for ( i = 0 ; i < face->nprops && !found; i++ )
347    {
348      if ( !strcmp( properties[i].name, prop ) )
349        found = 1;
350    }
351
352    if ( found )
353      return properties + i - 1;
354    else
355      return NULL;
356  }
357
358
359  static
360  FT_Error  pcf_get_properties( FT_Stream  stream,
361                                PCF_Face   face )
362  {
363    PCF_ParseProperty  props      = 0;
364    PCF_Property       properties = 0;
365    int                nprops, i;
366    FT_ULong           format, size;
367    FT_Error           error;
368    FT_Memory          memory     = FT_FACE(face)->memory;
369    FT_ULong           string_size;
370    FT_String*         strings    = 0;
371
372
373    error = pcfSeekToType( stream,
374                           face->toc.tables,
375                           face->toc.count,
376                           PCF_PROPERTIES,
377                           &format,
378                           &size );
379    if ( error )
380      goto Bail;
381
382    if ( READ_ULongLE( format ) )
383      goto Bail;
384
385    FT_TRACE4(( "get_prop: format = %ld\n", format ));
386
387    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
388      goto Bail;
389
390    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
391      (void)READ_ULong( nprops );
392    else
393      (void)READ_ULongLE( nprops );
394    if ( error )
395      goto Bail;
396
397    FT_TRACE4(( "get_prop: nprop = %d\n", nprops ));
398
399    if ( ALLOC( props, nprops * sizeof ( PCF_ParsePropertyRec ) ) )
400      goto Bail;
401
402    for ( i = 0; i < nprops; i++ )
403    {
404      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
405      {
406        if ( READ_Fields( pcf_property_msb_header, props + i ) )
407          goto Bail;
408      }
409      else
410      {
411        if ( READ_Fields( pcf_property_header, props + i ) )
412          goto Bail;
413      }
414    }
415
416    /* pad the property array                                            */
417    /*                                                                   */
418    /* clever here - nprops is the same as the number of odd-units read, */
419    /* as only isStringProp are odd length   (Keith Packard)             */
420    /*                                                                   */
421    if ( nprops & 3 )
422    {
423      i = 4 - ( nprops & 3 );
424      FT_Skip_Stream( stream, i );
425    }
426
427    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
428      (void)READ_ULong( string_size );
429    else
430      (void)READ_ULongLE( string_size );
431    if ( error )
432      goto Bail;
433
434    FT_TRACE4(( "get_prop: string_size = %ld\n", string_size ));
435
436    if ( ALLOC( strings, string_size * sizeof ( char ) ) )
437      goto Bail;
438
439    error = FT_Read_Stream( stream, (FT_Byte*)strings, string_size );
440    if ( error )
441      goto Bail;
442
443    if ( ALLOC( properties, nprops * sizeof ( PCF_PropertyRec ) ) )
444      goto Bail;
445
446    for ( i = 0; i < nprops; i++ )
447    {
448      /* XXX: make atom */
449      if ( ALLOC( properties[i].name,
450                     ( strlen( strings + props[i].name ) + 1 ) *
451                       sizeof ( char ) ) )
452        goto Bail;
453      strcpy( properties[i].name,strings + props[i].name );
454
455      properties[i].isString = props[i].isString;
456
457      if ( props[i].isString )
458      {
459        if ( ALLOC( properties[i].value.atom,
460                       ( strlen( strings + props[i].value ) + 1 ) *
461                         sizeof ( char ) ) )
462          goto Bail;
463        strcpy( properties[i].value.atom, strings + props[i].value );
464      }
465      else
466        properties[i].value.integer = props[i].value;
467    }
468
469    face->properties = properties;
470    face->nprops = nprops;
471
472    FREE( props );
473    FREE( strings );
474
475    return PCF_Err_Ok;
476
477  Bail:
478    FREE( props );
479    FREE( strings );
480
481    return error;
482  }
483
484
485  static
486  FT_Error  pcf_get_metrics( FT_Stream  stream,
487                             PCF_Face   face )
488  {
489    FT_Error    error    = PCF_Err_Ok;
490    FT_Memory   memory   = FT_FACE(face)->memory;
491    FT_ULong    format   = 0;
492    FT_ULong    size     = 0;
493    PCF_Metric  metrics  = 0;
494    int         i;
495    int         nmetrics = -1;
496
497
498    error = pcfSeekToType( stream,
499                           face->toc.tables,
500                           face->toc.count,
501                           PCF_METRICS,
502                           &format,
503                           &size );
504    if ( error )
505      return error;
506
507    error = READ_ULongLE( format );
508
509    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )   &&
510         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
511      return PCF_Err_Invalid_File_Format;
512
513    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
514    {
515      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
516        (void)READ_ULong( nmetrics );
517      else
518        (void)READ_ULongLE( nmetrics );
519    }
520    else
521    {
522      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
523        (void)READ_UShort( nmetrics );
524      else
525        (void)READ_UShortLE( nmetrics );
526    }
527    if ( error || nmetrics == -1 )
528      return PCF_Err_Invalid_File_Format;
529
530    face->nmetrics = nmetrics;
531
532    if ( ALLOC( face->metrics, nmetrics * sizeof ( PCF_MetricRec ) ) )
533      return PCF_Err_Out_Of_Memory;
534
535    metrics = face->metrics;
536    for ( i = 0; i < nmetrics; i++ )
537    {
538      pcf_get_metric( stream, format, metrics + i );
539
540      metrics[i].bits = 0;
541
542      FT_TRACE4(( "%d : width=%d, "
543                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
544                  i,
545                  ( metrics + i )->characterWidth,
546                  ( metrics + i )->leftSideBearing,
547                  ( metrics + i )->rightSideBearing,
548                  ( metrics + i )->ascent,
549                  ( metrics + i )->descent,
550                  ( metrics + i )->attributes ));
551
552      if ( error )
553        break;
554    }
555
556    if ( error )
557      FREE( face->metrics );
558    return error;
559  }
560
561
562  static
563  FT_Error  pcf_get_bitmaps( FT_Stream  stream,
564                             PCF_Face   face )
565  {
566    FT_Error   error  = PCF_Err_Ok;
567    FT_Memory  memory = FT_FACE(face)->memory;
568    FT_Long*   offsets;
569    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
570    FT_ULong   format, size;
571    int        nbitmaps, i, sizebitmaps = 0;
572    char*      bitmaps;
573
574
575    error = pcfSeekToType( stream,
576                           face->toc.tables,
577                           face->toc.count,
578                           PCF_BITMAPS,
579                           &format,
580                           &size );
581    if ( error )
582      return error;
583
584    error = FT_Access_Frame( stream, 8 );
585    if ( error )
586      return error;
587    format = GET_ULongLE();
588    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
589      return PCF_Err_Invalid_File_Format;
590
591    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
592      nbitmaps  = GET_ULong();
593    else
594      nbitmaps  = GET_ULongLE();
595    FT_Forget_Frame( stream );
596    if ( nbitmaps != face->nmetrics )
597      return PCF_Err_Invalid_File_Format;
598
599    if ( ALLOC( offsets, nbitmaps * sizeof ( FT_ULong ) ) )
600      return error;
601
602    if ( error )
603      goto Bail;
604    for ( i = 0; i < nbitmaps; i++ )
605    {
606      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
607        (void)READ_Long( offsets[i] );
608      else
609        (void)READ_LongLE( offsets[i] );
610
611      FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] ));
612    }
613    if ( error )
614      goto Bail;
615
616    if ( error )
617      goto Bail;
618    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
619    {
620      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
621        (void)READ_Long( bitmapSizes[i] );
622      else
623        (void)READ_LongLE( bitmapSizes[i] );
624      if ( error )
625        goto Bail;
626
627      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
628
629      FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
630    }
631
632    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
633                nbitmaps,
634                PCF_GLYPH_PAD_INDEX( format ) ));
635    FT_TRACE4(( "bitmap size = %d\n", sizebitmaps ));
636
637    for ( i = 0; i < nbitmaps; i++ )
638      face->metrics[i].bits = stream->pos + offsets[i];
639
640    face->bitmapsFormat = format;
641
642    FREE ( offsets );
643    return error;
644
645  Bail:
646    FREE ( offsets );
647    FREE ( bitmaps );
648    return error;
649  }
650
651
652  static
653  FT_Error  pcf_get_encodings( FT_Stream  stream,
654                               PCF_Face   face )
655  {
656    FT_Error      error   = PCF_Err_Ok;
657    FT_Memory     memory  = FT_FACE(face)->memory;
658    FT_ULong      format, size;
659    int           firstCol, lastCol;
660    int           firstRow, lastRow;
661    int           nencoding, encodingOffset;
662    int           i, j;
663    PCF_Encoding  tmpEncoding, encoding = 0;
664
665
666    error = pcfSeekToType( stream,
667                           face->toc.tables,
668                           face->toc.count,
669                           PCF_BDF_ENCODINGS,
670                           &format,
671                           &size );
672    if ( error )
673      return error;
674
675    error = FT_Access_Frame( stream, 14 );
676    if ( error )
677      return error;
678    format = GET_ULongLE();
679    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
680      return PCF_Err_Invalid_File_Format;
681
682    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
683    {
684      firstCol          = GET_Short();
685      lastCol           = GET_Short();
686      firstRow          = GET_Short();
687      lastRow           = GET_Short();
688      face->defaultChar = GET_Short();
689    }
690    else
691    {
692      firstCol          = GET_ShortLE();
693      lastCol           = GET_ShortLE();
694      firstRow          = GET_ShortLE();
695      lastRow           = GET_ShortLE();
696      face->defaultChar = GET_ShortLE();
697    }
698
699    FT_Forget_Frame( stream );
700
701    FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
702                firstCol, lastCol, firstRow, lastRow ));
703
704    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
705
706    if ( ALLOC( tmpEncoding, nencoding * sizeof ( PCF_EncodingRec ) ) )
707      return PCF_Err_Out_Of_Memory;
708
709    error = FT_Access_Frame( stream, 2 * nencoding );
710    if ( error )
711      goto Bail;
712
713    for ( i = 0, j = 0 ; i < nencoding; i++ )
714    {
715      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
716        encodingOffset = GET_Short();
717      else
718        encodingOffset = GET_ShortLE();
719
720      if ( encodingOffset != 0xFFFF )
721      {
722        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
723                                 firstRow ) * 256 ) +
724                               ( ( i % ( lastCol - firstCol + 1 ) ) +
725                                 firstCol );
726
727        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
728        j++;
729      }
730
731      FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n",
732                  i, tmpEncoding[j - 1].enc, encodingOffset ));
733    }
734    FT_Forget_Frame( stream );
735
736    if ( ALLOC( encoding, (--j) * sizeof ( PCF_EncodingRec ) ) )
737      goto Bail;
738
739    for ( i = 0; i < j; i++ )
740    {
741      encoding[i].enc   = tmpEncoding[i].enc;
742      encoding[i].glyph = tmpEncoding[i].glyph;
743    }
744
745    face->nencodings = j;
746    face->encodings  = encoding;
747    FREE( tmpEncoding );
748
749    return error;
750
751  Bail:
752    FREE( encoding );
753    FREE( tmpEncoding );
754    return error;
755  }
756
757
758  static
759  const FT_Frame_Field  pcf_accel_header[] =
760  {
761#undef  FT_STRUCTURE
762#define FT_STRUCTURE  PCF_AccelRec
763
764    FT_FRAME_START( 20 ),
765      FT_FRAME_BYTE      ( noOverlap ),
766      FT_FRAME_BYTE      ( constantMetrics ),
767      FT_FRAME_BYTE      ( terminalFont ),
768      FT_FRAME_BYTE      ( constantWidth ),
769      FT_FRAME_BYTE      ( inkInside ),
770      FT_FRAME_BYTE      ( inkMetrics ),
771      FT_FRAME_BYTE      ( drawDirection ),
772      FT_FRAME_SKIP_BYTES( 1 ),
773      FT_FRAME_LONG_LE   ( fontAscent ),
774      FT_FRAME_LONG_LE   ( fontDescent ),
775      FT_FRAME_LONG_LE   ( maxOverlap ),
776    FT_FRAME_END
777  };
778
779
780  static
781  const FT_Frame_Field  pcf_accel_msb_header[] =
782  {
783#undef  FT_STRUCTURE
784#define FT_STRUCTURE  PCF_AccelRec
785
786    FT_FRAME_START( 20 ),
787      FT_FRAME_BYTE      ( noOverlap ),
788      FT_FRAME_BYTE      ( constantMetrics ),
789      FT_FRAME_BYTE      ( terminalFont ),
790      FT_FRAME_BYTE      ( constantWidth ),
791      FT_FRAME_BYTE      ( inkInside ),
792      FT_FRAME_BYTE      ( inkMetrics ),
793      FT_FRAME_BYTE      ( drawDirection ),
794      FT_FRAME_SKIP_BYTES( 1 ),
795      FT_FRAME_LONG      ( fontAscent ),
796      FT_FRAME_LONG      ( fontDescent ),
797      FT_FRAME_LONG      ( maxOverlap ),
798    FT_FRAME_END
799  };
800
801
802  static
803  FT_Error  pcf_get_accel( FT_Stream  stream,
804                           PCF_Face   face,
805                           FT_ULong   type )
806  {
807    FT_ULong   format, size;
808    FT_Error   error = PCF_Err_Ok;
809    PCF_Accel  accel = &face->accel;
810
811
812    error = pcfSeekToType( stream,
813                           face->toc.tables,
814                           face->toc.count,
815                           type,
816                           &format,
817                           &size );
818    if ( error )
819      goto Bail;
820
821    error = READ_ULongLE( format );
822    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )  &&
823         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
824      goto Bail;
825
826    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
827    {
828      if ( READ_Fields( pcf_accel_msb_header, accel ) )
829        goto Bail;
830    }
831    else
832    {
833      if ( READ_Fields( pcf_accel_header, accel ) )
834        goto Bail;
835    }
836
837    error = pcf_get_metric( stream, format, &(accel->minbounds) );
838    if ( error )
839      goto Bail;
840    error = pcf_get_metric( stream, format, &(accel->maxbounds) );
841    if ( error )
842      goto Bail;
843
844    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
845    {
846      error = pcf_get_metric( stream, format, &(accel->ink_minbounds) );
847      if ( error )
848        goto Bail;
849      error = pcf_get_metric( stream, format, &(accel->ink_maxbounds) );
850      if ( error )
851        goto Bail;
852    }
853    else
854    {
855      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
856      accel->ink_maxbounds = accel->maxbounds;
857    }
858    return error;
859
860  Bail:
861    return error;
862  }
863
864
865  FT_LOCAL_DEF
866  FT_Error  pcf_load_font( FT_Stream  stream,
867                           PCF_Face   face )
868  {
869    FT_Error   error  = PCF_Err_Ok;
870    FT_Memory  memory = FT_FACE(face)->memory;
871    FT_Bool    hasBDFAccelerators;
872
873
874    error = pcf_read_TOC( stream, face );
875    if ( error )
876      return error;
877
878    error = pcf_get_properties( stream, face );
879    if ( error )
880      return error;;
881
882    /* Use the old accelerators if no BDF accelerators are in the file. */
883    hasBDFAccelerators = pcfHasType( face->toc.tables,
884                                     face->toc.count,
885                                     PCF_BDF_ACCELERATORS );
886    if ( !hasBDFAccelerators )
887    {
888      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
889      if ( error )
890        goto Bail;
891    }
892
893    /* metrics */
894    error = pcf_get_metrics( stream, face );
895    if ( error )
896      goto Bail;
897
898    /* bitmaps */
899    error = pcf_get_bitmaps( stream, face );
900    if ( error )
901      goto Bail;
902
903    /* encodings */
904    error = pcf_get_encodings( stream, face );
905    if ( error )
906      goto Bail;
907
908    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
909    if ( hasBDFAccelerators )
910    {
911      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
912      if ( error )
913        goto Bail;
914    }
915
916    /* XXX: TO DO: inkmetrics and glyph_names are missing */
917
918    /* now construct the face object */
919    {
920      FT_Face       root = FT_FACE( face );
921      PCF_Property  prop;
922
923
924      root->num_faces = 1;
925      root->face_index = 0;
926      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
927                         FT_FACE_FLAG_HORIZONTAL  |
928                         FT_FACE_FLAG_FAST_GLYPHS;
929
930      if ( face->accel.constantWidth )
931        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
932
933      root->style_flags = 0;
934      prop = find_property( face, "SLANT" );
935      if ( prop != NULL )
936        if ( prop->isString )
937          if ( ( *(prop->value.atom) == 'O' ) ||
938               ( *(prop->value.atom) == 'I' ) )
939            root->style_flags |= FT_STYLE_FLAG_ITALIC;
940
941      prop = find_property( face, "WEIGHT_NAME" );
942      if ( prop != NULL )
943        if ( prop->isString )
944          if ( *(prop->value.atom) == 'B' )
945            root->style_flags |= FT_STYLE_FLAG_BOLD;
946
947      root->style_name = (char *)"Regular";
948
949      if ( root->style_flags & FT_STYLE_FLAG_BOLD ) {
950        if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
951          root->style_name = (char *)"Bold Italic";
952        else
953          root->style_name = (char *)"Bold";
954      }
955      else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
956        root->style_name = (char *)"Italic";
957
958      prop = find_property( face, "FAMILY_NAME" );
959      if ( prop != NULL )
960      {
961        if ( prop->isString )
962        {
963          int  l = strlen( prop->value.atom ) + 1;
964
965
966          if ( ALLOC( root->family_name, l * sizeof ( char ) ) )
967            goto Bail;
968          strcpy( root->family_name, prop->value.atom );
969        }
970      }
971      else
972        root->family_name = 0;
973
974      root->num_glyphs = face->nmetrics;
975
976      root->num_fixed_sizes = 1;
977      if ( ALLOC_ARRAY( root->available_sizes, 1, FT_Bitmap_Size ) )
978        goto Bail;
979
980      prop = find_property( face, "PIXEL_SIZE" );
981      if ( prop != NULL )
982      {
983        PCF_Property  xres = 0, yres = 0;
984
985
986        xres = find_property( face, "RESOLUTION_X" );
987        yres = find_property( face, "RESOLUTION_Y" );
988        if ( ( xres != NULL ) && ( yres != NULL ) )
989        {
990          root->available_sizes->width =
991            (FT_Short)( prop->value.integer * 75 / xres->value.integer );
992          root->available_sizes->height =
993            (FT_Short)( prop->value.integer * 75 / yres->value.integer );
994        }
995      }
996      else
997      { /* XXX */
998#if 0
999        printf( "PCF Warning: Pixel Size undefined, assuming 12\n");
1000#endif
1001        root->available_sizes->width = 12;
1002        root->available_sizes->height = 12;
1003      }
1004
1005      /* XXX: charmaps */
1006      root->charmaps     = &face->charmap_handle;
1007      root->num_charmaps = 1;
1008
1009      {
1010        PCF_Property  charset_registry = 0, charset_encoding = 0;
1011
1012
1013        charset_registry = find_property( face, "CHARSET_REGISTRY" );
1014        charset_encoding = find_property( face, "CHARSET_ENCODING" );
1015
1016        if ( ( charset_registry != NULL ) &&
1017             ( charset_encoding != NULL ) )
1018        {
1019          if ( ( charset_registry->isString ) &&
1020               ( charset_encoding->isString ) )
1021          {
1022            if ( ALLOC( face->charset_encoding,
1023                        ( strlen( charset_encoding->value.atom ) + 1 ) *
1024                          sizeof ( char ) ) )
1025              goto Bail;
1026            if ( ALLOC( face->charset_registry,
1027                        ( strlen( charset_registry->value.atom ) + 1 ) *
1028                          sizeof ( char ) ) )
1029              goto Bail;
1030            strcpy( face->charset_registry, charset_registry->value.atom );
1031            strcpy( face->charset_encoding, charset_encoding->value.atom );
1032
1033#if 0
1034            if ( !strcmp( charset_registry, "ISO10646" ) )
1035            {
1036              face->charmap.encoding    = ft_encoding_unicode;
1037              face->charmap.platform_id = 3;
1038              face->charmap.encoding_id = 1;
1039              face->charmap.face        = root;
1040              face->charmap_handle
1041
1042              return PCF_Err_Ok;
1043            }
1044#endif
1045          }
1046        }
1047      }
1048
1049      face->charmap.encoding    = ft_encoding_none;
1050      face->charmap.platform_id = 0;
1051      face->charmap.encoding_id = 0;
1052      face->charmap.face        = root;
1053      face->charmap_handle      = &face->charmap;
1054      root->charmap             = face->charmap_handle;
1055    }
1056    return PCF_Err_Ok;
1057
1058  Bail:
1059    PCF_Done_Face( face );
1060    return PCF_Err_Invalid_File_Format;
1061  }
1062
1063
1064/* END */
1065