pcfread.c revision 10bf05a31d63c6674fd057514d1066d1f081f4aa
1/*  pcfread.c
2
3    FreeType font driver for pcf fonts
4
5  Copyright 2000, 2001, 2002, 2003, 2004 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 "pcfdrivr.h"
36#include "pcfread.h"
37
38#include "pcferror.h"
39
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 const char* const  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 FT_Error
89  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    FT_UInt    n;
98
99
100    if ( FT_STREAM_SEEK ( 0 )                          ||
101         FT_STREAM_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 ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
108      return PCF_Err_Out_Of_Memory;
109
110    tables = face->toc.tables;
111    for ( n = 0; n < toc->count; n++ )
112    {
113      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
114        goto Exit;
115      tables++;
116    }
117
118#if defined( FT_DEBUG_LEVEL_TRACE )
119
120    {
121      FT_UInt      i, j;
122      const 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 == (FT_UInt)( 1 << j ) )
131            name = tableNames[j];
132
133        FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX "
134                    "size=0x%06lX (%8ld) offset=0x%04lX\n",
135                    i, name,
136                    tables[i].format,
137                    tables[i].size, tables[i].size,
138                    tables[i].offset ));
139      }
140    }
141
142#endif
143
144    return PCF_Err_Ok;
145
146  Exit:
147    FT_FREE( face->toc.tables );
148    return error;
149  }
150
151
152  static
153  const FT_Frame_Field  pcf_metric_header[] =
154  {
155#undef  FT_STRUCTURE
156#define FT_STRUCTURE  PCF_MetricRec
157
158    FT_FRAME_START( 12 ),
159      FT_FRAME_SHORT_LE( leftSideBearing ),
160      FT_FRAME_SHORT_LE( rightSideBearing ),
161      FT_FRAME_SHORT_LE( characterWidth ),
162      FT_FRAME_SHORT_LE( ascent ),
163      FT_FRAME_SHORT_LE( descent ),
164      FT_FRAME_SHORT_LE( attributes ),
165    FT_FRAME_END
166  };
167
168
169  static
170  const FT_Frame_Field  pcf_metric_msb_header[] =
171  {
172#undef  FT_STRUCTURE
173#define FT_STRUCTURE  PCF_MetricRec
174
175    FT_FRAME_START( 12 ),
176      FT_FRAME_SHORT( leftSideBearing ),
177      FT_FRAME_SHORT( rightSideBearing ),
178      FT_FRAME_SHORT( characterWidth ),
179      FT_FRAME_SHORT( ascent ),
180      FT_FRAME_SHORT( descent ),
181      FT_FRAME_SHORT( attributes ),
182    FT_FRAME_END
183  };
184
185
186  static
187  const FT_Frame_Field  pcf_compressed_metric_header[] =
188  {
189#undef  FT_STRUCTURE
190#define FT_STRUCTURE  PCF_Compressed_MetricRec
191
192    FT_FRAME_START( 5 ),
193      FT_FRAME_BYTE( leftSideBearing ),
194      FT_FRAME_BYTE( rightSideBearing ),
195      FT_FRAME_BYTE( characterWidth ),
196      FT_FRAME_BYTE( ascent ),
197      FT_FRAME_BYTE( descent ),
198    FT_FRAME_END
199  };
200
201
202  static FT_Error
203  pcf_get_metric( FT_Stream   stream,
204                  FT_ULong    format,
205                  PCF_Metric  metric )
206  {
207    FT_Error  error = PCF_Err_Ok;
208
209
210    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
211    {
212      const FT_Frame_Field*  fields;
213
214
215      /* parsing normal metrics */
216      fields = PCF_BYTE_ORDER( format ) == MSBFirst
217               ? pcf_metric_msb_header
218               : pcf_metric_header;
219
220      /* the following sets 'error' but doesn't return in case of failure */
221      (void)FT_STREAM_READ_FIELDS( fields, metric );
222    }
223    else
224    {
225      PCF_Compressed_MetricRec  compr;
226
227
228      /* parsing compressed metrics */
229      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
230        goto Exit;
231
232      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
233      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
234      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
235      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
236      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
237      metric->attributes       = 0;
238    }
239
240  Exit:
241    return error;
242  }
243
244
245  static FT_Error
246  pcf_seek_to_table_type( FT_Stream  stream,
247                          PCF_Table  tables,
248                          FT_Int     ntables,
249                          FT_ULong   type,
250                          FT_ULong  *aformat,
251                          FT_ULong  *asize )
252  {
253    FT_Error  error = PCF_Err_Invalid_File_Format;
254    FT_Int    i;
255
256
257    for ( i = 0; i < ntables; i++ )
258      if ( tables[i].type == type )
259      {
260        if ( stream->pos > tables[i].offset ) {
261          error = PCF_Err_Invalid_Stream_Skip;
262          goto Fail;
263        }
264
265        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) {
266          error = PCF_Err_Invalid_Stream_Skip;
267          goto Fail;
268        }
269
270        *asize   = tables[i].size;  /* unused - to be removed */
271        *aformat = tables[i].format;
272
273        return PCF_Err_Ok;
274      }
275
276  Fail:
277    return error;
278  }
279
280
281  static FT_Bool
282  pcf_has_table_type( PCF_Table  tables,
283                      FT_Int     ntables,
284                      FT_ULong   type )
285  {
286    FT_Int  i;
287
288
289    for ( i = 0; i < ntables; i++ )
290      if ( tables[i].type == type )
291        return TRUE;
292
293    return FALSE;
294  }
295
296
297  static
298  const FT_Frame_Field  pcf_property_header[] =
299  {
300#undef  FT_STRUCTURE
301#define FT_STRUCTURE  PCF_ParsePropertyRec
302
303    FT_FRAME_START( 9 ),
304      FT_FRAME_LONG_LE( name ),
305      FT_FRAME_BYTE   ( isString ),
306      FT_FRAME_LONG_LE( value ),
307    FT_FRAME_END
308  };
309
310
311  static
312  const FT_Frame_Field  pcf_property_msb_header[] =
313  {
314#undef  FT_STRUCTURE
315#define FT_STRUCTURE  PCF_ParsePropertyRec
316
317    FT_FRAME_START( 9 ),
318      FT_FRAME_LONG( name ),
319      FT_FRAME_BYTE( isString ),
320      FT_FRAME_LONG( value ),
321    FT_FRAME_END
322  };
323
324
325  FT_LOCAL_DEF( PCF_Property )
326  pcf_find_property( PCF_Face          face,
327                     const FT_String*  prop )
328  {
329    PCF_Property  properties = face->properties;
330    FT_Bool       found      = 0;
331    int           i;
332
333
334    for ( i = 0 ; i < face->nprops && !found; i++ )
335    {
336      if ( !ft_strcmp( properties[i].name, prop ) )
337        found = 1;
338    }
339
340    if ( found )
341      return properties + i - 1;
342    else
343      return NULL;
344  }
345
346
347  static FT_Error
348  pcf_get_properties( FT_Stream  stream,
349                      PCF_Face   face )
350  {
351    PCF_ParseProperty  props      = 0;
352    PCF_Property       properties = 0;
353    FT_Int             nprops, i;
354    FT_ULong           format, size;
355    FT_Error           error;
356    FT_Memory          memory     = FT_FACE(face)->memory;
357    FT_ULong           string_size;
358    FT_String*         strings    = 0;
359
360
361    error = pcf_seek_to_table_type( stream,
362                                    face->toc.tables,
363                                    face->toc.count,
364                                    PCF_PROPERTIES,
365                                    &format,
366                                    &size );
367    if ( error )
368      goto Bail;
369
370    if ( FT_READ_ULONG_LE( format ) )
371      goto Bail;
372
373    FT_TRACE4(( "get_prop: format = %ld\n", format ));
374
375    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
376      goto Bail;
377
378    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
379      (void)FT_READ_ULONG( nprops );
380    else
381      (void)FT_READ_ULONG_LE( nprops );
382    if ( error )
383      goto Bail;
384
385    FT_TRACE4(( "get_prop: nprop = %d\n", nprops ));
386
387    if ( FT_NEW_ARRAY( props, nprops ) )
388      goto Bail;
389
390    for ( i = 0; i < nprops; i++ )
391    {
392      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
393      {
394        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
395          goto Bail;
396      }
397      else
398      {
399        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
400          goto Bail;
401      }
402    }
403
404    /* pad the property array                                            */
405    /*                                                                   */
406    /* clever here - nprops is the same as the number of odd-units read, */
407    /* as only isStringProp are odd length   (Keith Packard)             */
408    /*                                                                   */
409    if ( nprops & 3 )
410    {
411      i = 4 - ( nprops & 3 );
412      FT_Stream_Skip( stream, i );
413    }
414
415    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
416      (void)FT_READ_ULONG( string_size );
417    else
418      (void)FT_READ_ULONG_LE( string_size );
419    if ( error )
420      goto Bail;
421
422    FT_TRACE4(( "get_prop: string_size = %ld\n", string_size ));
423
424    if ( FT_NEW_ARRAY( strings, string_size ) )
425      goto Bail;
426
427    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
428    if ( error )
429      goto Bail;
430
431    if ( FT_NEW_ARRAY( properties, nprops ) )
432      goto Bail;
433
434    for ( i = 0; i < nprops; i++ )
435    {
436      /* XXX: make atom */
437      if ( FT_NEW_ARRAY( properties[i].name,
438                         ft_strlen( strings + props[i].name ) + 1 ) )
439        goto Bail;
440      ft_strcpy( properties[i].name,strings + props[i].name );
441
442      properties[i].isString = props[i].isString;
443
444      if ( props[i].isString )
445      {
446        if ( FT_NEW_ARRAY( properties[i].value.atom,
447                           ft_strlen( strings + props[i].value ) + 1 ) )
448          goto Bail;
449        ft_strcpy( properties[i].value.atom, strings + props[i].value );
450      }
451      else
452        properties[i].value.integer = props[i].value;
453    }
454
455    face->properties = properties;
456    face->nprops = nprops;
457
458    FT_FREE( props );
459    FT_FREE( strings );
460
461    return PCF_Err_Ok;
462
463  Bail:
464    FT_FREE( props );
465    FT_FREE( strings );
466
467    return error;
468  }
469
470
471  static FT_Error
472  pcf_get_metrics( FT_Stream  stream,
473                   PCF_Face   face )
474  {
475    FT_Error    error    = PCF_Err_Ok;
476    FT_Memory   memory   = FT_FACE(face)->memory;
477    FT_ULong    format   = 0;
478    FT_ULong    size     = 0;
479    PCF_Metric  metrics  = 0;
480    int         i;
481    int         nmetrics = -1;
482
483
484    error = pcf_seek_to_table_type( stream,
485                                    face->toc.tables,
486                                    face->toc.count,
487                                    PCF_METRICS,
488                                    &format,
489                                    &size );
490    if ( error )
491      return error;
492
493    error = FT_READ_ULONG_LE( format );
494
495    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
496         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
497      return PCF_Err_Invalid_File_Format;
498
499    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
500    {
501      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
502        (void)FT_READ_ULONG( nmetrics );
503      else
504        (void)FT_READ_ULONG_LE( nmetrics );
505    }
506    else
507    {
508      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
509        (void)FT_READ_USHORT( nmetrics );
510      else
511        (void)FT_READ_USHORT_LE( nmetrics );
512    }
513    if ( error || nmetrics == -1 )
514      return PCF_Err_Invalid_File_Format;
515
516    face->nmetrics = nmetrics;
517
518    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
519      return PCF_Err_Out_Of_Memory;
520
521    metrics = face->metrics;
522    for ( i = 0; i < nmetrics; i++ )
523    {
524      pcf_get_metric( stream, format, metrics + i );
525
526      metrics[i].bits = 0;
527
528      FT_TRACE4(( "%d : width=%d, "
529                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
530                  i,
531                  ( metrics + i )->characterWidth,
532                  ( metrics + i )->leftSideBearing,
533                  ( metrics + i )->rightSideBearing,
534                  ( metrics + i )->ascent,
535                  ( metrics + i )->descent,
536                  ( metrics + i )->attributes ));
537
538      if ( error )
539        break;
540    }
541
542    if ( error )
543      FT_FREE( face->metrics );
544    return error;
545  }
546
547
548  static FT_Error
549  pcf_get_bitmaps( FT_Stream  stream,
550                   PCF_Face   face )
551  {
552    FT_Error   error  = PCF_Err_Ok;
553    FT_Memory  memory = FT_FACE(face)->memory;
554    FT_Long*   offsets;
555    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
556    FT_ULong   format, size;
557    int        nbitmaps, i, sizebitmaps = 0;
558    char*      bitmaps;
559
560
561    error = pcf_seek_to_table_type( stream,
562                                    face->toc.tables,
563                                    face->toc.count,
564                                    PCF_BITMAPS,
565                                    &format,
566                                    &size );
567    if ( error )
568      return error;
569
570    error = FT_Stream_EnterFrame( stream, 8 );
571    if ( error )
572      return error;
573
574    format = FT_GET_ULONG_LE();
575    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
576      nbitmaps  = FT_GET_ULONG();
577    else
578      nbitmaps  = FT_GET_ULONG_LE();
579
580    FT_Stream_ExitFrame( stream );
581
582    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
583      return PCF_Err_Invalid_File_Format;
584
585    if ( nbitmaps != face->nmetrics )
586      return PCF_Err_Invalid_File_Format;
587
588    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
589      return error;
590
591    for ( i = 0; i < nbitmaps; i++ )
592    {
593      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
594        (void)FT_READ_LONG( offsets[i] );
595      else
596        (void)FT_READ_LONG_LE( offsets[i] );
597
598      FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] ));
599    }
600    if ( error )
601      goto Bail;
602
603    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
604    {
605      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
606        (void)FT_READ_LONG( bitmapSizes[i] );
607      else
608        (void)FT_READ_LONG_LE( bitmapSizes[i] );
609      if ( error )
610        goto Bail;
611
612      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
613
614      FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
615    }
616
617    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
618                nbitmaps,
619                PCF_GLYPH_PAD_INDEX( format ) ));
620    FT_TRACE4(( "bitmap size = %d\n", sizebitmaps ));
621
622    FT_UNUSED( sizebitmaps );       /* only used for debugging */
623
624    for ( i = 0; i < nbitmaps; i++ )
625      face->metrics[i].bits = stream->pos + offsets[i];
626
627    face->bitmapsFormat = format;
628
629    FT_FREE ( offsets );
630    return error;
631
632  Bail:
633    FT_FREE ( offsets );
634    FT_FREE ( bitmaps );
635    return error;
636  }
637
638
639  static FT_Error
640  pcf_get_encodings( FT_Stream  stream,
641                     PCF_Face   face )
642  {
643    FT_Error      error   = PCF_Err_Ok;
644    FT_Memory     memory  = FT_FACE(face)->memory;
645    FT_ULong      format, size;
646    int           firstCol, lastCol;
647    int           firstRow, lastRow;
648    int           nencoding, encodingOffset;
649    int           i, j;
650    PCF_Encoding  tmpEncoding, encoding = 0;
651
652
653    error = pcf_seek_to_table_type( stream,
654                                    face->toc.tables,
655                                    face->toc.count,
656                                    PCF_BDF_ENCODINGS,
657                                    &format,
658                                    &size );
659    if ( error )
660      return error;
661
662    error = FT_Stream_EnterFrame( stream, 14 );
663    if ( error )
664      return error;
665
666    format = FT_GET_ULONG_LE();
667
668    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
669    {
670      firstCol          = FT_GET_SHORT();
671      lastCol           = FT_GET_SHORT();
672      firstRow          = FT_GET_SHORT();
673      lastRow           = FT_GET_SHORT();
674      face->defaultChar = FT_GET_SHORT();
675    }
676    else
677    {
678      firstCol          = FT_GET_SHORT_LE();
679      lastCol           = FT_GET_SHORT_LE();
680      firstRow          = FT_GET_SHORT_LE();
681      lastRow           = FT_GET_SHORT_LE();
682      face->defaultChar = FT_GET_SHORT_LE();
683    }
684
685    FT_Stream_ExitFrame( stream );
686
687    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
688      return PCF_Err_Invalid_File_Format;
689
690    FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
691                firstCol, lastCol, firstRow, lastRow ));
692
693    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
694
695    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
696      return PCF_Err_Out_Of_Memory;
697
698    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
699    if ( error )
700      goto Bail;
701
702    for ( i = 0, j = 0 ; i < nencoding; i++ )
703    {
704      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
705        encodingOffset = FT_GET_SHORT();
706      else
707        encodingOffset = FT_GET_SHORT_LE();
708
709      if ( encodingOffset != -1 )
710      {
711        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
712                                 firstRow ) * 256 ) +
713                               ( ( i % ( lastCol - firstCol + 1 ) ) +
714                                 firstCol );
715
716        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
717        j++;
718      }
719
720      FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n",
721                  i, tmpEncoding[j - 1].enc, encodingOffset ));
722    }
723    FT_Stream_ExitFrame( stream );
724
725    if ( FT_NEW_ARRAY( encoding, j ) )
726      goto Bail;
727
728    for ( i = 0; i < j; i++ )
729    {
730      encoding[i].enc   = tmpEncoding[i].enc;
731      encoding[i].glyph = tmpEncoding[i].glyph;
732    }
733
734    face->nencodings = j;
735    face->encodings  = encoding;
736    FT_FREE( tmpEncoding );
737
738    return error;
739
740  Bail:
741    FT_FREE( encoding );
742    FT_FREE( tmpEncoding );
743    return error;
744  }
745
746
747  static
748  const FT_Frame_Field  pcf_accel_header[] =
749  {
750#undef  FT_STRUCTURE
751#define FT_STRUCTURE  PCF_AccelRec
752
753    FT_FRAME_START( 20 ),
754      FT_FRAME_BYTE      ( noOverlap ),
755      FT_FRAME_BYTE      ( constantMetrics ),
756      FT_FRAME_BYTE      ( terminalFont ),
757      FT_FRAME_BYTE      ( constantWidth ),
758      FT_FRAME_BYTE      ( inkInside ),
759      FT_FRAME_BYTE      ( inkMetrics ),
760      FT_FRAME_BYTE      ( drawDirection ),
761      FT_FRAME_SKIP_BYTES( 1 ),
762      FT_FRAME_LONG_LE   ( fontAscent ),
763      FT_FRAME_LONG_LE   ( fontDescent ),
764      FT_FRAME_LONG_LE   ( maxOverlap ),
765    FT_FRAME_END
766  };
767
768
769  static
770  const FT_Frame_Field  pcf_accel_msb_header[] =
771  {
772#undef  FT_STRUCTURE
773#define FT_STRUCTURE  PCF_AccelRec
774
775    FT_FRAME_START( 20 ),
776      FT_FRAME_BYTE      ( noOverlap ),
777      FT_FRAME_BYTE      ( constantMetrics ),
778      FT_FRAME_BYTE      ( terminalFont ),
779      FT_FRAME_BYTE      ( constantWidth ),
780      FT_FRAME_BYTE      ( inkInside ),
781      FT_FRAME_BYTE      ( inkMetrics ),
782      FT_FRAME_BYTE      ( drawDirection ),
783      FT_FRAME_SKIP_BYTES( 1 ),
784      FT_FRAME_LONG      ( fontAscent ),
785      FT_FRAME_LONG      ( fontDescent ),
786      FT_FRAME_LONG      ( maxOverlap ),
787    FT_FRAME_END
788  };
789
790
791  static FT_Error
792  pcf_get_accel( FT_Stream  stream,
793                 PCF_Face   face,
794                 FT_ULong   type )
795  {
796    FT_ULong   format, size;
797    FT_Error   error = PCF_Err_Ok;
798    PCF_Accel  accel = &face->accel;
799
800
801    error = pcf_seek_to_table_type( stream,
802                                    face->toc.tables,
803                                    face->toc.count,
804                                    type,
805                                    &format,
806                                    &size );
807    if ( error )
808      goto Bail;
809
810    error = FT_READ_ULONG_LE( format );
811
812    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
813         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
814      goto Bail;
815
816    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
817    {
818      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
819        goto Bail;
820    }
821    else
822    {
823      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
824        goto Bail;
825    }
826
827    error = pcf_get_metric( stream,
828                            format & ( ~PCF_FORMAT_MASK ),
829                            &(accel->minbounds) );
830    if ( error )
831      goto Bail;
832
833    error = pcf_get_metric( stream,
834                            format & ( ~PCF_FORMAT_MASK ),
835                            &(accel->maxbounds) );
836    if ( error )
837      goto Bail;
838
839    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
840    {
841      error = pcf_get_metric( stream,
842                              format & ( ~PCF_FORMAT_MASK ),
843                              &(accel->ink_minbounds) );
844      if ( error )
845        goto Bail;
846
847      error = pcf_get_metric( stream,
848                              format & ( ~PCF_FORMAT_MASK ),
849                              &(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  static FT_Error
866  pcf_interpret_style( PCF_Face  pcf )
867  {
868    FT_Error   error  = PCF_Err_Ok;
869    FT_Face    face   = FT_FACE( pcf );
870    FT_Memory  memory = face->memory;
871
872    PCF_Property  prop;
873
874    char  *istr = NULL, *bstr = NULL;
875    char  *sstr = NULL, *astr = NULL;
876
877    int  parts = 0, len = 0;
878
879
880    face->style_flags = 0;
881
882    prop = pcf_find_property( pcf, "SLANT" );
883    if ( prop && prop->isString                                       &&
884         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
885           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
886    {
887      face->style_flags |= FT_STYLE_FLAG_ITALIC;
888      istr = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' )
889               ? (char *)"Oblique"
890               : (char *)"Italic";
891      len += ft_strlen( istr );
892      parts++;
893    }
894
895    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
896    if ( prop && prop->isString                                       &&
897         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
898    {
899      face->style_flags |= FT_STYLE_FLAG_BOLD;
900      bstr = (char *)"Bold";
901      len += ft_strlen( bstr );
902      parts++;
903    }
904
905    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
906    if ( prop && prop->isString                                        &&
907         *(prop->value.atom)                                           &&
908         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
909    {
910      sstr = (char *)(prop->value.atom);
911      len += ft_strlen( sstr );
912      parts++;
913    }
914
915    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
916    if ( prop && prop->isString                                        &&
917         *(prop->value.atom)                                           &&
918         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
919    {
920      astr = (char *)(prop->value.atom);
921      len += ft_strlen( astr );
922      parts++;
923    }
924
925    if ( !parts || !len )
926      face->style_name = (char *)"Regular";
927    else
928    {
929      char          *style, *s;
930      unsigned int  i;
931
932
933      if ( FT_ALLOC( style, len + parts ) )
934        return error;
935
936      s = style;
937
938      if ( astr )
939      {
940        ft_strcpy( s, astr );
941        for ( i = 0; i < ft_strlen( astr ); i++, s++ )
942          if ( *s == ' ' )
943            *s = '-';                     /* replace spaces with dashes */
944        *(s++) = ' ';
945      }
946      if ( bstr )
947      {
948        ft_strcpy( s, bstr );
949        s += ft_strlen( bstr );
950        *(s++) = ' ';
951      }
952      if ( istr )
953      {
954        ft_strcpy( s, istr );
955        s += ft_strlen( istr );
956        *(s++) = ' ';
957      }
958      if ( sstr )
959      {
960        ft_strcpy( s, sstr );
961        for ( i = 0; i < ft_strlen( sstr ); i++, s++ )
962          if ( *s == ' ' )
963            *s = '-';                     /* replace spaces with dashes */
964        *(s++) = ' ';
965      }
966      *(--s) = '\0';        /* overwrite last ' ', terminate the string */
967
968      face->style_name = style;                     /* allocated string */
969    }
970
971    return error;
972  }
973
974
975  FT_LOCAL_DEF( FT_Error )
976  pcf_load_font( FT_Stream  stream,
977                 PCF_Face   face )
978  {
979    FT_Error   error  = PCF_Err_Ok;
980    FT_Memory  memory = FT_FACE(face)->memory;
981    FT_Bool    hasBDFAccelerators;
982
983
984    error = pcf_read_TOC( stream, face );
985    if ( error )
986      goto Exit;
987
988    error = pcf_get_properties( stream, face );
989    if ( error )
990      goto Exit;
991
992    /* Use the old accelerators if no BDF accelerators are in the file. */
993    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
994                                             face->toc.count,
995                                             PCF_BDF_ACCELERATORS );
996    if ( !hasBDFAccelerators )
997    {
998      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
999      if ( error )
1000        goto Exit;
1001    }
1002
1003    /* metrics */
1004    error = pcf_get_metrics( stream, face );
1005    if ( error )
1006      goto Exit;
1007
1008    /* bitmaps */
1009    error = pcf_get_bitmaps( stream, face );
1010    if ( error )
1011      goto Exit;
1012
1013    /* encodings */
1014    error = pcf_get_encodings( stream, face );
1015    if ( error )
1016      goto Exit;
1017
1018    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1019    if ( hasBDFAccelerators )
1020    {
1021      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1022      if ( error )
1023        goto Exit;
1024    }
1025
1026    /* XXX: TO DO: inkmetrics and glyph_names are missing */
1027
1028    /* now construct the face object */
1029    {
1030      FT_Face       root = FT_FACE( face );
1031      PCF_Property  prop;
1032
1033
1034      root->num_faces  = 1;
1035      root->face_index = 0;
1036      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1037                         FT_FACE_FLAG_HORIZONTAL  |
1038                         FT_FACE_FLAG_FAST_GLYPHS;
1039
1040      if ( face->accel.constantWidth )
1041        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1042
1043      if ( ( error = pcf_interpret_style( face ) ) != 0 )
1044         goto Exit;
1045
1046      prop = pcf_find_property( face, "FAMILY_NAME" );
1047      if ( prop && prop->isString )
1048      {
1049        int  l = ft_strlen( prop->value.atom ) + 1;
1050
1051
1052        if ( FT_NEW_ARRAY( root->family_name, l ) )
1053          goto Exit;
1054        ft_strcpy( root->family_name, prop->value.atom );
1055      }
1056      else
1057        root->family_name = NULL;
1058
1059      /* Note: We shift all glyph indices by +1 since we must
1060       * respect the convention that glyph 0 always corresponds
1061       * to the "missing glyph".
1062       *
1063       * This implies bumping the number of "available" glyphs by 1.
1064       */
1065      root->num_glyphs = face->nmetrics + 1;
1066
1067      root->num_fixed_sizes = 1;
1068      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1069        goto Exit;
1070
1071      {
1072        FT_Bitmap_Size*  bsize = root->available_sizes;
1073        FT_Short         resolution_x = 0, resolution_y = 0;
1074
1075
1076        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1077
1078        bsize->height = face->accel.fontAscent + face->accel.fontDescent;
1079
1080        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1081        if ( prop )
1082          bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 );
1083        else
1084          bsize->width = bsize->height * 2/3;
1085
1086        prop = pcf_find_property( face, "POINT_SIZE" );
1087        if ( prop )
1088          /* convert from 722.7 decipoints to 72 points per inch */
1089          bsize->size =
1090            (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L );
1091
1092        prop = pcf_find_property( face, "PIXEL_SIZE" );
1093        if ( prop )
1094          bsize->y_ppem = (FT_Short)prop->value.integer << 6;
1095
1096        prop = pcf_find_property( face, "RESOLUTION_X" );
1097        if ( prop )
1098          resolution_x = (FT_Short)prop->value.integer;
1099
1100        prop = pcf_find_property( face, "RESOLUTION_Y" );
1101        if ( prop )
1102          resolution_y = (FT_Short)prop->value.integer;
1103
1104        if ( bsize->y_ppem == 0 )
1105        {
1106          bsize->y_ppem = bsize->size;
1107          if ( resolution_y )
1108            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1109        }
1110        if ( resolution_x && resolution_y )
1111          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1112        else
1113          bsize->x_ppem = bsize->y_ppem;
1114      }
1115
1116      /* set up charset */
1117      {
1118        PCF_Property  charset_registry = 0, charset_encoding = 0;
1119
1120
1121        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1122        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1123
1124        if ( charset_registry && charset_registry->isString &&
1125             charset_encoding && charset_encoding->isString )
1126        {
1127          if ( FT_NEW_ARRAY( face->charset_encoding,
1128                             ft_strlen( charset_encoding->value.atom ) + 1 ) )
1129            goto Exit;
1130
1131          if ( FT_NEW_ARRAY( face->charset_registry,
1132                             ft_strlen( charset_registry->value.atom ) + 1 ) )
1133            goto Exit;
1134
1135          ft_strcpy( face->charset_registry, charset_registry->value.atom );
1136          ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
1137        }
1138      }
1139    }
1140
1141  Exit:
1142    if ( error )
1143    {
1144      /* this is done to respect the behaviour of the original */
1145      /* PCF font driver.                                      */
1146      error = PCF_Err_Invalid_File_Format;
1147    }
1148
1149    return error;
1150  }
1151
1152
1153/* END */
1154