Initialize Tizen 2.3
[framework/graphics/freetype.git] / src / pcf / pcfread.c
1 /*  pcfread.c
2
3     FreeType font driver for pcf fonts
4
5   Copyright 2000-2010, 2012 by
6   Francesco Zappa Nardelli
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE 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 "pcfread.h"
36
37 #include "pcferror.h"
38
39
40   /*************************************************************************/
41   /*                                                                       */
42   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
43   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
44   /* messages during execution.                                            */
45   /*                                                                       */
46 #undef  FT_COMPONENT
47 #define FT_COMPONENT  trace_pcfread
48
49
50 #ifdef FT_DEBUG_LEVEL_TRACE
51   static const char* const  tableNames[] =
52   {
53     "prop", "accl", "mtrcs", "bmps", "imtrcs",
54     "enc", "swidth", "names", "accel"
55   };
56 #endif
57
58
59   static
60   const FT_Frame_Field  pcf_toc_header[] =
61   {
62 #undef  FT_STRUCTURE
63 #define FT_STRUCTURE  PCF_TocRec
64
65     FT_FRAME_START( 8 ),
66       FT_FRAME_ULONG_LE( version ),
67       FT_FRAME_ULONG_LE( count ),
68     FT_FRAME_END
69   };
70
71
72   static
73   const FT_Frame_Field  pcf_table_header[] =
74   {
75 #undef  FT_STRUCTURE
76 #define FT_STRUCTURE  PCF_TableRec
77
78     FT_FRAME_START( 16  ),
79       FT_FRAME_ULONG_LE( type ),
80       FT_FRAME_ULONG_LE( format ),
81       FT_FRAME_ULONG_LE( size ),
82       FT_FRAME_ULONG_LE( offset ),
83     FT_FRAME_END
84   };
85
86
87   static FT_Error
88   pcf_read_TOC( FT_Stream  stream,
89                 PCF_Face   face )
90   {
91     FT_Error   error;
92     PCF_Toc    toc = &face->toc;
93     PCF_Table  tables;
94
95     FT_Memory  memory = FT_FACE(face)->memory;
96     FT_UInt    n;
97
98
99     if ( FT_STREAM_SEEK ( 0 )                          ||
100          FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
101       return PCF_Err_Cannot_Open_Resource;
102
103     if ( toc->version != PCF_FILE_VERSION                 ||
104          toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
105          toc->count   == 0                                )
106       return PCF_Err_Invalid_File_Format;
107
108     if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
109       return PCF_Err_Out_Of_Memory;
110
111     tables = face->toc.tables;
112     for ( n = 0; n < toc->count; n++ )
113     {
114       if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
115         goto Exit;
116       tables++;
117     }
118
119     /* Sort tables and check for overlaps.  Because they are almost      */
120     /* always ordered already, an in-place bubble sort with simultaneous */
121     /* boundary checking seems appropriate.                              */
122     tables = face->toc.tables;
123
124     for ( n = 0; n < toc->count - 1; n++ )
125     {
126       FT_UInt  i, have_change;
127
128
129       have_change = 0;
130
131       for ( i = 0; i < toc->count - 1 - n; i++ )
132       {
133         PCF_TableRec  tmp;
134
135
136         if ( tables[i].offset > tables[i + 1].offset )
137         {
138           tmp           = tables[i];
139           tables[i]     = tables[i + 1];
140           tables[i + 1] = tmp;
141
142           have_change = 1;
143         }
144
145         if ( ( tables[i].size   > tables[i + 1].offset )                  ||
146              ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
147           return PCF_Err_Invalid_Offset;
148       }
149
150       if ( !have_change )
151         break;
152     }
153
154 #ifdef FT_DEBUG_LEVEL_TRACE
155
156     {
157       FT_UInt      i, j;
158       const char*  name = "?";
159
160
161       FT_TRACE4(( "pcf_read_TOC:\n" ));
162
163       FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
164
165       tables = face->toc.tables;
166       for ( i = 0; i < toc->count; i++ )
167       {
168         for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
169               j++ )
170           if ( tables[i].type == (FT_UInt)( 1 << j ) )
171             name = tableNames[j];
172
173         FT_TRACE4(( "  %d: type=%s, format=0x%X, "
174                     "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
175                     i, name,
176                     tables[i].format,
177                     tables[i].size, tables[i].size,
178                     tables[i].offset, tables[i].offset ));
179       }
180     }
181
182 #endif
183
184     return PCF_Err_Ok;
185
186   Exit:
187     FT_FREE( face->toc.tables );
188     return error;
189   }
190
191
192 #define PCF_METRIC_SIZE  12
193
194   static
195   const FT_Frame_Field  pcf_metric_header[] =
196   {
197 #undef  FT_STRUCTURE
198 #define FT_STRUCTURE  PCF_MetricRec
199
200     FT_FRAME_START( PCF_METRIC_SIZE ),
201       FT_FRAME_SHORT_LE( leftSideBearing ),
202       FT_FRAME_SHORT_LE( rightSideBearing ),
203       FT_FRAME_SHORT_LE( characterWidth ),
204       FT_FRAME_SHORT_LE( ascent ),
205       FT_FRAME_SHORT_LE( descent ),
206       FT_FRAME_SHORT_LE( attributes ),
207     FT_FRAME_END
208   };
209
210
211   static
212   const FT_Frame_Field  pcf_metric_msb_header[] =
213   {
214 #undef  FT_STRUCTURE
215 #define FT_STRUCTURE  PCF_MetricRec
216
217     FT_FRAME_START( PCF_METRIC_SIZE ),
218       FT_FRAME_SHORT( leftSideBearing ),
219       FT_FRAME_SHORT( rightSideBearing ),
220       FT_FRAME_SHORT( characterWidth ),
221       FT_FRAME_SHORT( ascent ),
222       FT_FRAME_SHORT( descent ),
223       FT_FRAME_SHORT( attributes ),
224     FT_FRAME_END
225   };
226
227
228 #define PCF_COMPRESSED_METRIC_SIZE  5
229
230   static
231   const FT_Frame_Field  pcf_compressed_metric_header[] =
232   {
233 #undef  FT_STRUCTURE
234 #define FT_STRUCTURE  PCF_Compressed_MetricRec
235
236     FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
237       FT_FRAME_BYTE( leftSideBearing ),
238       FT_FRAME_BYTE( rightSideBearing ),
239       FT_FRAME_BYTE( characterWidth ),
240       FT_FRAME_BYTE( ascent ),
241       FT_FRAME_BYTE( descent ),
242     FT_FRAME_END
243   };
244
245
246   static FT_Error
247   pcf_get_metric( FT_Stream   stream,
248                   FT_ULong    format,
249                   PCF_Metric  metric )
250   {
251     FT_Error  error = PCF_Err_Ok;
252
253
254     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
255     {
256       const FT_Frame_Field*  fields;
257
258
259       /* parsing normal metrics */
260       fields = PCF_BYTE_ORDER( format ) == MSBFirst
261                ? pcf_metric_msb_header
262                : pcf_metric_header;
263
264       /* the following sets `error' but doesn't return in case of failure */
265       (void)FT_STREAM_READ_FIELDS( fields, metric );
266     }
267     else
268     {
269       PCF_Compressed_MetricRec  compr;
270
271
272       /* parsing compressed metrics */
273       if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
274         goto Exit;
275
276       metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
277       metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
278       metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
279       metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
280       metric->descent          = (FT_Short)( compr.descent          - 0x80 );
281       metric->attributes       = 0;
282     }
283
284   Exit:
285     return error;
286   }
287
288
289   static FT_Error
290   pcf_seek_to_table_type( FT_Stream  stream,
291                           PCF_Table  tables,
292                           FT_ULong   ntables, /* same as PCF_Toc->count */
293                           FT_ULong   type,
294                           FT_ULong  *aformat,
295                           FT_ULong  *asize )
296   {
297     FT_Error  error = PCF_Err_Invalid_File_Format;
298     FT_ULong  i;
299
300
301     for ( i = 0; i < ntables; i++ )
302       if ( tables[i].type == type )
303       {
304         if ( stream->pos > tables[i].offset )
305         {
306           error = PCF_Err_Invalid_Stream_Skip;
307           goto Fail;
308         }
309
310         if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
311         {
312           error = PCF_Err_Invalid_Stream_Skip;
313           goto Fail;
314         }
315
316         *asize   = tables[i].size;
317         *aformat = tables[i].format;
318
319         return PCF_Err_Ok;
320       }
321
322   Fail:
323     *asize = 0;
324     return error;
325   }
326
327
328   static FT_Bool
329   pcf_has_table_type( PCF_Table  tables,
330                       FT_ULong   ntables, /* same as PCF_Toc->count */
331                       FT_ULong   type )
332   {
333     FT_ULong  i;
334
335
336     for ( i = 0; i < ntables; i++ )
337       if ( tables[i].type == type )
338         return TRUE;
339
340     return FALSE;
341   }
342
343
344 #define PCF_PROPERTY_SIZE  9
345
346   static
347   const FT_Frame_Field  pcf_property_header[] =
348   {
349 #undef  FT_STRUCTURE
350 #define FT_STRUCTURE  PCF_ParsePropertyRec
351
352     FT_FRAME_START( PCF_PROPERTY_SIZE ),
353       FT_FRAME_LONG_LE( name ),
354       FT_FRAME_BYTE   ( isString ),
355       FT_FRAME_LONG_LE( value ),
356     FT_FRAME_END
357   };
358
359
360   static
361   const FT_Frame_Field  pcf_property_msb_header[] =
362   {
363 #undef  FT_STRUCTURE
364 #define FT_STRUCTURE  PCF_ParsePropertyRec
365
366     FT_FRAME_START( PCF_PROPERTY_SIZE ),
367       FT_FRAME_LONG( name ),
368       FT_FRAME_BYTE( isString ),
369       FT_FRAME_LONG( value ),
370     FT_FRAME_END
371   };
372
373
374   FT_LOCAL_DEF( PCF_Property )
375   pcf_find_property( PCF_Face          face,
376                      const FT_String*  prop )
377   {
378     PCF_Property  properties = face->properties;
379     FT_Bool       found      = 0;
380     int           i;
381
382
383     for ( i = 0 ; i < face->nprops && !found; i++ )
384     {
385       if ( !ft_strcmp( properties[i].name, prop ) )
386         found = 1;
387     }
388
389     if ( found )
390       return properties + i - 1;
391     else
392       return NULL;
393   }
394
395
396   static FT_Error
397   pcf_get_properties( FT_Stream  stream,
398                       PCF_Face   face )
399   {
400     PCF_ParseProperty  props      = 0;
401     PCF_Property       properties = NULL;
402     FT_ULong           nprops, i;
403     FT_ULong           format, size;
404     FT_Error           error;
405     FT_Memory          memory     = FT_FACE(face)->memory;
406     FT_ULong           string_size;
407     FT_String*         strings    = 0;
408
409
410     error = pcf_seek_to_table_type( stream,
411                                     face->toc.tables,
412                                     face->toc.count,
413                                     PCF_PROPERTIES,
414                                     &format,
415                                     &size );
416     if ( error )
417       goto Bail;
418
419     if ( FT_READ_ULONG_LE( format ) )
420       goto Bail;
421
422     FT_TRACE4(( "pcf_get_properties:\n" ));
423
424     FT_TRACE4(( "  format = %ld\n", format ));
425
426     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
427       goto Bail;
428
429     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
430       (void)FT_READ_ULONG( nprops );
431     else
432       (void)FT_READ_ULONG_LE( nprops );
433     if ( error )
434       goto Bail;
435
436     FT_TRACE4(( "  nprop = %d (truncate %d props)\n",
437                 (int)nprops, nprops - (int)nprops ));
438
439     nprops = (int)nprops;
440
441     /* rough estimate */
442     if ( nprops > size / PCF_PROPERTY_SIZE )
443     {
444       error = PCF_Err_Invalid_Table;
445       goto Bail;
446     }
447
448     face->nprops = (int)nprops;
449
450     if ( FT_NEW_ARRAY( props, nprops ) )
451       goto Bail;
452
453     for ( i = 0; i < nprops; i++ )
454     {
455       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
456       {
457         if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
458           goto Bail;
459       }
460       else
461       {
462         if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
463           goto Bail;
464       }
465     }
466
467     /* pad the property array                                            */
468     /*                                                                   */
469     /* clever here - nprops is the same as the number of odd-units read, */
470     /* as only isStringProp are odd length   (Keith Packard)             */
471     /*                                                                   */
472     if ( nprops & 3 )
473     {
474       i = 4 - ( nprops & 3 );
475       if ( FT_STREAM_SKIP( i ) )
476       {
477         error = PCF_Err_Invalid_Stream_Skip;
478         goto Bail;
479       }
480     }
481
482     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
483       (void)FT_READ_ULONG( string_size );
484     else
485       (void)FT_READ_ULONG_LE( string_size );
486     if ( error )
487       goto Bail;
488
489     FT_TRACE4(( "  string_size = %ld\n", string_size ));
490
491     /* rough estimate */
492     if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
493     {
494       error = PCF_Err_Invalid_Table;
495       goto Bail;
496     }
497
498     /* allocate one more byte so that we have a final null byte */
499     if ( FT_NEW_ARRAY( strings, string_size + 1 ) )
500       goto Bail;
501
502     error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
503     if ( error )
504       goto Bail;
505
506     if ( FT_NEW_ARRAY( properties, nprops ) )
507       goto Bail;
508
509     face->properties = properties;
510
511     for ( i = 0; i < nprops; i++ )
512     {
513       FT_Long  name_offset = props[i].name;
514
515
516       if ( ( name_offset < 0 )                     ||
517            ( (FT_ULong)name_offset > string_size ) )
518       {
519         error = PCF_Err_Invalid_Offset;
520         goto Bail;
521       }
522
523       if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
524         goto Bail;
525
526       FT_TRACE4(( "  %s:", properties[i].name ));
527
528       properties[i].isString = props[i].isString;
529
530       if ( props[i].isString )
531       {
532         FT_Long  value_offset = props[i].value;
533
534
535         if ( ( value_offset < 0 )                     ||
536              ( (FT_ULong)value_offset > string_size ) )
537         {
538           error = PCF_Err_Invalid_Offset;
539           goto Bail;
540         }
541
542         if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
543           goto Bail;
544
545         FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
546       }
547       else
548       {
549         properties[i].value.l = props[i].value;
550
551         FT_TRACE4(( " %d\n", properties[i].value.l ));
552       }
553     }
554
555     error = PCF_Err_Ok;
556
557   Bail:
558     FT_FREE( props );
559     FT_FREE( strings );
560
561     return error;
562   }
563
564
565   static FT_Error
566   pcf_get_metrics( FT_Stream  stream,
567                    PCF_Face   face )
568   {
569     FT_Error    error    = PCF_Err_Ok;
570     FT_Memory   memory   = FT_FACE(face)->memory;
571     FT_ULong    format, size;
572     PCF_Metric  metrics  = 0;
573     FT_ULong    nmetrics, i;
574
575
576     error = pcf_seek_to_table_type( stream,
577                                     face->toc.tables,
578                                     face->toc.count,
579                                     PCF_METRICS,
580                                     &format,
581                                     &size );
582     if ( error )
583       return error;
584
585     if ( FT_READ_ULONG_LE( format ) )
586       goto Bail;
587
588     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
589          !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
590       return PCF_Err_Invalid_File_Format;
591
592     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
593     {
594       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
595         (void)FT_READ_ULONG( nmetrics );
596       else
597         (void)FT_READ_ULONG_LE( nmetrics );
598     }
599     else
600     {
601       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
602         (void)FT_READ_USHORT( nmetrics );
603       else
604         (void)FT_READ_USHORT_LE( nmetrics );
605     }
606     if ( error )
607       return PCF_Err_Invalid_File_Format;
608
609     face->nmetrics = nmetrics;
610
611     if ( !nmetrics )
612       return PCF_Err_Invalid_Table;
613
614     FT_TRACE4(( "pcf_get_metrics:\n" ));
615
616     FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
617
618     /* rough estimate */
619     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
620     {
621       if ( nmetrics > size / PCF_METRIC_SIZE )
622         return PCF_Err_Invalid_Table;
623     }
624     else
625     {
626       if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
627         return PCF_Err_Invalid_Table;
628     }
629
630     if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
631       return PCF_Err_Out_Of_Memory;
632
633     metrics = face->metrics;
634     for ( i = 0; i < nmetrics; i++ )
635     {
636       error = pcf_get_metric( stream, format, metrics + i );
637
638       metrics[i].bits = 0;
639
640       FT_TRACE5(( "  idx %d: width=%d, "
641                   "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
642                   i,
643                   ( metrics + i )->characterWidth,
644                   ( metrics + i )->leftSideBearing,
645                   ( metrics + i )->rightSideBearing,
646                   ( metrics + i )->ascent,
647                   ( metrics + i )->descent,
648                   ( metrics + i )->attributes ));
649
650       if ( error )
651         break;
652     }
653
654     if ( error )
655       FT_FREE( face->metrics );
656
657   Bail:
658     return error;
659   }
660
661
662   static FT_Error
663   pcf_get_bitmaps( FT_Stream  stream,
664                    PCF_Face   face )
665   {
666     FT_Error   error   = PCF_Err_Ok;
667     FT_Memory  memory  = FT_FACE(face)->memory;
668     FT_Long*   offsets = NULL;
669     FT_Long    bitmapSizes[GLYPHPADOPTIONS];
670     FT_ULong   format, size;
671     FT_ULong   nbitmaps, i, sizebitmaps = 0;
672
673
674     error = pcf_seek_to_table_type( stream,
675                                     face->toc.tables,
676                                     face->toc.count,
677                                     PCF_BITMAPS,
678                                     &format,
679                                     &size );
680     if ( error )
681       return error;
682
683     error = FT_Stream_EnterFrame( stream, 8 );
684     if ( error )
685       return error;
686
687     format = FT_GET_ULONG_LE();
688     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
689       nbitmaps  = FT_GET_ULONG();
690     else
691       nbitmaps  = FT_GET_ULONG_LE();
692
693     FT_Stream_ExitFrame( stream );
694
695     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
696       return PCF_Err_Invalid_File_Format;
697
698     FT_TRACE4(( "pcf_get_bitmaps:\n" ));
699
700     FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
701
702     /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
703     if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
704       return PCF_Err_Invalid_File_Format;
705
706     if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
707       return error;
708
709     for ( i = 0; i < nbitmaps; i++ )
710     {
711       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
712         (void)FT_READ_LONG( offsets[i] );
713       else
714         (void)FT_READ_LONG_LE( offsets[i] );
715
716       FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
717                   i, offsets[i], offsets[i] ));
718     }
719     if ( error )
720       goto Bail;
721
722     for ( i = 0; i < GLYPHPADOPTIONS; i++ )
723     {
724       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
725         (void)FT_READ_LONG( bitmapSizes[i] );
726       else
727         (void)FT_READ_LONG_LE( bitmapSizes[i] );
728       if ( error )
729         goto Bail;
730
731       sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
732
733       FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
734     }
735
736     FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
737                 nbitmaps,
738                 PCF_GLYPH_PAD_INDEX( format ) ));
739     FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
740
741     FT_UNUSED( sizebitmaps );       /* only used for debugging */
742
743     for ( i = 0; i < nbitmaps; i++ )
744     {
745       /* rough estimate */
746       if ( ( offsets[i] < 0 )              ||
747            ( (FT_ULong)offsets[i] > size ) )
748       {
749         FT_TRACE0(( "pcf_get_bitmaps:"
750                     " invalid offset to bitmap data of glyph %d\n", i ));
751       }
752       else
753         face->metrics[i].bits = stream->pos + offsets[i];
754     }
755
756     face->bitmapsFormat = format;
757
758   Bail:
759     FT_FREE( offsets );
760     return error;
761   }
762
763
764   static FT_Error
765   pcf_get_encodings( FT_Stream  stream,
766                      PCF_Face   face )
767   {
768     FT_Error      error  = PCF_Err_Ok;
769     FT_Memory     memory = FT_FACE(face)->memory;
770     FT_ULong      format, size;
771     int           firstCol, lastCol;
772     int           firstRow, lastRow;
773     int           nencoding, encodingOffset;
774     int           i, j;
775     PCF_Encoding  tmpEncoding = NULL, encoding = 0;
776
777
778     error = pcf_seek_to_table_type( stream,
779                                     face->toc.tables,
780                                     face->toc.count,
781                                     PCF_BDF_ENCODINGS,
782                                     &format,
783                                     &size );
784     if ( error )
785       return error;
786
787     error = FT_Stream_EnterFrame( stream, 14 );
788     if ( error )
789       return error;
790
791     format = FT_GET_ULONG_LE();
792
793     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
794     {
795       firstCol          = FT_GET_SHORT();
796       lastCol           = FT_GET_SHORT();
797       firstRow          = FT_GET_SHORT();
798       lastRow           = FT_GET_SHORT();
799       face->defaultChar = FT_GET_SHORT();
800     }
801     else
802     {
803       firstCol          = FT_GET_SHORT_LE();
804       lastCol           = FT_GET_SHORT_LE();
805       firstRow          = FT_GET_SHORT_LE();
806       lastRow           = FT_GET_SHORT_LE();
807       face->defaultChar = FT_GET_SHORT_LE();
808     }
809
810     FT_Stream_ExitFrame( stream );
811
812     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
813       return PCF_Err_Invalid_File_Format;
814
815     FT_TRACE4(( "pdf_get_encodings:\n" ));
816
817     FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
818                 firstCol, lastCol, firstRow, lastRow ));
819
820     nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
821
822     if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
823       return PCF_Err_Out_Of_Memory;
824
825     error = FT_Stream_EnterFrame( stream, 2 * nencoding );
826     if ( error )
827       goto Bail;
828
829     for ( i = 0, j = 0 ; i < nencoding; i++ )
830     {
831       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
832         encodingOffset = FT_GET_SHORT();
833       else
834         encodingOffset = FT_GET_SHORT_LE();
835
836       if ( encodingOffset != -1 )
837       {
838         tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
839                                  firstRow ) * 256 ) +
840                                ( ( i % ( lastCol - firstCol + 1 ) ) +
841                                  firstCol );
842
843         tmpEncoding[j].glyph = (FT_Short)encodingOffset;
844
845         FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
846                     tmpEncoding[j].enc, tmpEncoding[j].enc,
847                     tmpEncoding[j].glyph ));
848
849         j++;
850       }
851     }
852     FT_Stream_ExitFrame( stream );
853
854     if ( FT_NEW_ARRAY( encoding, j ) )
855       goto Bail;
856
857     for ( i = 0; i < j; i++ )
858     {
859       encoding[i].enc   = tmpEncoding[i].enc;
860       encoding[i].glyph = tmpEncoding[i].glyph;
861     }
862
863     face->nencodings = j;
864     face->encodings  = encoding;
865     FT_FREE( tmpEncoding );
866
867     return error;
868
869   Bail:
870     FT_FREE( encoding );
871     FT_FREE( tmpEncoding );
872     return error;
873   }
874
875
876   static
877   const FT_Frame_Field  pcf_accel_header[] =
878   {
879 #undef  FT_STRUCTURE
880 #define FT_STRUCTURE  PCF_AccelRec
881
882     FT_FRAME_START( 20 ),
883       FT_FRAME_BYTE      ( noOverlap ),
884       FT_FRAME_BYTE      ( constantMetrics ),
885       FT_FRAME_BYTE      ( terminalFont ),
886       FT_FRAME_BYTE      ( constantWidth ),
887       FT_FRAME_BYTE      ( inkInside ),
888       FT_FRAME_BYTE      ( inkMetrics ),
889       FT_FRAME_BYTE      ( drawDirection ),
890       FT_FRAME_SKIP_BYTES( 1 ),
891       FT_FRAME_LONG_LE   ( fontAscent ),
892       FT_FRAME_LONG_LE   ( fontDescent ),
893       FT_FRAME_LONG_LE   ( maxOverlap ),
894     FT_FRAME_END
895   };
896
897
898   static
899   const FT_Frame_Field  pcf_accel_msb_header[] =
900   {
901 #undef  FT_STRUCTURE
902 #define FT_STRUCTURE  PCF_AccelRec
903
904     FT_FRAME_START( 20 ),
905       FT_FRAME_BYTE      ( noOverlap ),
906       FT_FRAME_BYTE      ( constantMetrics ),
907       FT_FRAME_BYTE      ( terminalFont ),
908       FT_FRAME_BYTE      ( constantWidth ),
909       FT_FRAME_BYTE      ( inkInside ),
910       FT_FRAME_BYTE      ( inkMetrics ),
911       FT_FRAME_BYTE      ( drawDirection ),
912       FT_FRAME_SKIP_BYTES( 1 ),
913       FT_FRAME_LONG      ( fontAscent ),
914       FT_FRAME_LONG      ( fontDescent ),
915       FT_FRAME_LONG      ( maxOverlap ),
916     FT_FRAME_END
917   };
918
919
920   static FT_Error
921   pcf_get_accel( FT_Stream  stream,
922                  PCF_Face   face,
923                  FT_ULong   type )
924   {
925     FT_ULong   format, size;
926     FT_Error   error = PCF_Err_Ok;
927     PCF_Accel  accel = &face->accel;
928
929
930     error = pcf_seek_to_table_type( stream,
931                                     face->toc.tables,
932                                     face->toc.count,
933                                     type,
934                                     &format,
935                                     &size );
936     if ( error )
937       goto Bail;
938
939     if ( FT_READ_ULONG_LE( format ) )
940       goto Bail;
941
942     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
943          !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
944       goto Bail;
945
946     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
947     {
948       if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
949         goto Bail;
950     }
951     else
952     {
953       if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
954         goto Bail;
955     }
956
957     error = pcf_get_metric( stream,
958                             format & ( ~PCF_FORMAT_MASK ),
959                             &(accel->minbounds) );
960     if ( error )
961       goto Bail;
962
963     error = pcf_get_metric( stream,
964                             format & ( ~PCF_FORMAT_MASK ),
965                             &(accel->maxbounds) );
966     if ( error )
967       goto Bail;
968
969     if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
970     {
971       error = pcf_get_metric( stream,
972                               format & ( ~PCF_FORMAT_MASK ),
973                               &(accel->ink_minbounds) );
974       if ( error )
975         goto Bail;
976
977       error = pcf_get_metric( stream,
978                               format & ( ~PCF_FORMAT_MASK ),
979                               &(accel->ink_maxbounds) );
980       if ( error )
981         goto Bail;
982     }
983     else
984     {
985       accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
986       accel->ink_maxbounds = accel->maxbounds;
987     }
988
989   Bail:
990     return error;
991   }
992
993
994   static FT_Error
995   pcf_interpret_style( PCF_Face  pcf )
996   {
997     FT_Error   error  = PCF_Err_Ok;
998     FT_Face    face   = FT_FACE( pcf );
999     FT_Memory  memory = face->memory;
1000
1001     PCF_Property  prop;
1002
1003     size_t  nn, len;
1004     char*   strings[4] = { NULL, NULL, NULL, NULL };
1005     size_t  lengths[4];
1006
1007
1008     face->style_flags = 0;
1009
1010     prop = pcf_find_property( pcf, "SLANT" );
1011     if ( prop && prop->isString                                       &&
1012          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1013            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1014     {
1015       face->style_flags |= FT_STYLE_FLAG_ITALIC;
1016       strings[2] = ( *(prop->value.atom) == 'O' ||
1017                      *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1018                                                   : (char *)"Italic";
1019     }
1020
1021     prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1022     if ( prop && prop->isString                                       &&
1023          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1024     {
1025       face->style_flags |= FT_STYLE_FLAG_BOLD;
1026       strings[1] = (char *)"Bold";
1027     }
1028
1029     prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1030     if ( prop && prop->isString                                        &&
1031          *(prop->value.atom)                                           &&
1032          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1033       strings[3] = (char *)(prop->value.atom);
1034
1035     prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1036     if ( prop && prop->isString                                        &&
1037          *(prop->value.atom)                                           &&
1038          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1039       strings[0] = (char *)(prop->value.atom);
1040
1041     for ( len = 0, nn = 0; nn < 4; nn++ )
1042     {
1043       lengths[nn] = 0;
1044       if ( strings[nn] )
1045       {
1046         lengths[nn] = ft_strlen( strings[nn] );
1047         len        += lengths[nn] + 1;
1048       }
1049     }
1050
1051     if ( len == 0 )
1052     {
1053       strings[0] = (char *)"Regular";
1054       lengths[0] = ft_strlen( strings[0] );
1055       len        = lengths[0] + 1;
1056     }
1057
1058     {
1059       char*  s;
1060
1061
1062       if ( FT_ALLOC( face->style_name, len ) )
1063         return error;
1064
1065       s = face->style_name;
1066
1067       for ( nn = 0; nn < 4; nn++ )
1068       {
1069         char*  src = strings[nn];
1070
1071
1072         len = lengths[nn];
1073
1074         if ( src == NULL )
1075           continue;
1076
1077         /* separate elements with a space */
1078         if ( s != face->style_name )
1079           *s++ = ' ';
1080
1081         ft_memcpy( s, src, len );
1082
1083         /* need to convert spaces to dashes for */
1084         /* add_style_name and setwidth_name     */
1085         if ( nn == 0 || nn == 3 )
1086         {
1087           size_t  mm;
1088
1089
1090           for ( mm = 0; mm < len; mm++ )
1091             if (s[mm] == ' ')
1092               s[mm] = '-';
1093         }
1094
1095         s += len;
1096       }
1097       *s = 0;
1098     }
1099
1100     return error;
1101   }
1102
1103
1104   FT_LOCAL_DEF( FT_Error )
1105   pcf_load_font( FT_Stream  stream,
1106                  PCF_Face   face )
1107   {
1108     FT_Error   error  = PCF_Err_Ok;
1109     FT_Memory  memory = FT_FACE(face)->memory;
1110     FT_Bool    hasBDFAccelerators;
1111
1112
1113     error = pcf_read_TOC( stream, face );
1114     if ( error )
1115       goto Exit;
1116
1117     error = pcf_get_properties( stream, face );
1118     if ( error )
1119       goto Exit;
1120
1121     /* Use the old accelerators if no BDF accelerators are in the file. */
1122     hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1123                                              face->toc.count,
1124                                              PCF_BDF_ACCELERATORS );
1125     if ( !hasBDFAccelerators )
1126     {
1127       error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1128       if ( error )
1129         goto Exit;
1130     }
1131
1132     /* metrics */
1133     error = pcf_get_metrics( stream, face );
1134     if ( error )
1135       goto Exit;
1136
1137     /* bitmaps */
1138     error = pcf_get_bitmaps( stream, face );
1139     if ( error )
1140       goto Exit;
1141
1142     /* encodings */
1143     error = pcf_get_encodings( stream, face );
1144     if ( error )
1145       goto Exit;
1146
1147     /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1148     if ( hasBDFAccelerators )
1149     {
1150       error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1151       if ( error )
1152         goto Exit;
1153     }
1154
1155     /* XXX: TO DO: inkmetrics and glyph_names are missing */
1156
1157     /* now construct the face object */
1158     {
1159       FT_Face       root = FT_FACE( face );
1160       PCF_Property  prop;
1161
1162
1163       root->num_faces  = 1;
1164       root->face_index = 0;
1165       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1166                          FT_FACE_FLAG_HORIZONTAL  |
1167                          FT_FACE_FLAG_FAST_GLYPHS;
1168
1169       if ( face->accel.constantWidth )
1170         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1171
1172       if ( ( error = pcf_interpret_style( face ) ) != 0 )
1173          goto Exit;
1174
1175       prop = pcf_find_property( face, "FAMILY_NAME" );
1176       if ( prop && prop->isString )
1177       {
1178         if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1179           goto Exit;
1180       }
1181       else
1182         root->family_name = NULL;
1183
1184       /*
1185        * Note: We shift all glyph indices by +1 since we must
1186        * respect the convention that glyph 0 always corresponds
1187        * to the `missing glyph'.
1188        *
1189        * This implies bumping the number of `available' glyphs by 1.
1190        */
1191       root->num_glyphs = face->nmetrics + 1;
1192
1193       root->num_fixed_sizes = 1;
1194       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1195         goto Exit;
1196
1197       {
1198         FT_Bitmap_Size*  bsize = root->available_sizes;
1199         FT_Short         resolution_x = 0, resolution_y = 0;
1200
1201
1202         FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1203
1204 #if 0
1205         bsize->height = face->accel.maxbounds.ascent << 6;
1206 #endif
1207         bsize->height = (FT_Short)( face->accel.fontAscent +
1208                                     face->accel.fontDescent );
1209
1210         prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1211         if ( prop )
1212           bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1213         else
1214           bsize->width = (FT_Short)( bsize->height * 2/3 );
1215
1216         prop = pcf_find_property( face, "POINT_SIZE" );
1217         if ( prop )
1218           /* convert from 722.7 decipoints to 72 points per inch */
1219           bsize->size =
1220             (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1221
1222         prop = pcf_find_property( face, "PIXEL_SIZE" );
1223         if ( prop )
1224           bsize->y_ppem = (FT_Short)prop->value.l << 6;
1225
1226         prop = pcf_find_property( face, "RESOLUTION_X" );
1227         if ( prop )
1228           resolution_x = (FT_Short)prop->value.l;
1229
1230         prop = pcf_find_property( face, "RESOLUTION_Y" );
1231         if ( prop )
1232           resolution_y = (FT_Short)prop->value.l;
1233
1234         if ( bsize->y_ppem == 0 )
1235         {
1236           bsize->y_ppem = bsize->size;
1237           if ( resolution_y )
1238             bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1239         }
1240         if ( resolution_x && resolution_y )
1241           bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1242         else
1243           bsize->x_ppem = bsize->y_ppem;
1244       }
1245
1246       /* set up charset */
1247       {
1248         PCF_Property  charset_registry = 0, charset_encoding = 0;
1249
1250
1251         charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1252         charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1253
1254         if ( charset_registry && charset_registry->isString &&
1255              charset_encoding && charset_encoding->isString )
1256         {
1257           if ( FT_STRDUP( face->charset_encoding,
1258                           charset_encoding->value.atom ) ||
1259                FT_STRDUP( face->charset_registry,
1260                           charset_registry->value.atom ) )
1261             goto Exit;
1262         }
1263       }
1264     }
1265
1266   Exit:
1267     if ( error )
1268     {
1269       /* This is done to respect the behaviour of the original */
1270       /* PCF font driver.                                      */
1271       error = PCF_Err_Invalid_File_Format;
1272     }
1273
1274     return error;
1275   }
1276
1277
1278 /* END */