source: trunk/poppler/freetype2/src/pcf/pcfread.c @ 165

Last change on this file since 165 was 165, checked in by Eugene Romanenko, 15 years ago

update to latest freetype cvs, (closes #76)

File size: 34.9 KB
Line 
1/*  pcfread.c
2
3    FreeType font driver for pcf fonts
4
5  Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 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         toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
106         toc->count   == 0                                )
107      return PCF_Err_Invalid_File_Format;
108
109    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
110      return PCF_Err_Out_Of_Memory;
111
112    tables = face->toc.tables;
113    for ( n = 0; n < toc->count; n++ )
114    {
115      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
116        goto Exit;
117      tables++;
118    }
119
120    /* Sort tables and check for overlaps.  Because they are almost      */
121    /* always ordered already, an in-place bubble sort with simultaneous */
122    /* boundary checking seems appropriate.                              */
123    tables = face->toc.tables;
124
125    for ( n = 0; n < toc->count - 1; n++ )
126    {
127      FT_UInt  i, have_change;
128
129
130      have_change = 0;
131
132      for ( i = 0; i < toc->count - 1 - n; i++ )
133      {
134        PCF_TableRec  tmp;
135
136
137        if ( tables[i].offset > tables[i + 1].offset )
138        {
139          tmp           = tables[i];
140          tables[i]     = tables[i + 1];
141          tables[i + 1] = tmp;
142
143          have_change = 1;
144        }
145
146        if ( ( tables[i].size   > tables[i + 1].offset )                  ||
147             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
148          return PCF_Err_Invalid_Offset;
149      }
150
151      if ( !have_change )
152        break;
153    }
154
155#if defined( FT_DEBUG_LEVEL_TRACE )
156
157    {
158      FT_UInt      i, j;
159      const char*  name = "?";
160
161
162      FT_TRACE4(( "pcf_read_TOC:\n" ));
163
164      FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
165
166      tables = face->toc.tables;
167      for ( i = 0; i < toc->count; i++ )
168      {
169        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
170              j++ )
171          if ( tables[i].type == (FT_UInt)( 1 << j ) )
172            name = tableNames[j];
173
174        FT_TRACE4(( "  %d: type=%s, format=0x%X, "
175                    "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
176                    i, name,
177                    tables[i].format,
178                    tables[i].size, tables[i].size,
179                    tables[i].offset, tables[i].offset ));
180      }
181    }
182
183#endif
184
185    return PCF_Err_Ok;
186
187  Exit:
188    FT_FREE( face->toc.tables );
189    return error;
190  }
191
192
193#define PCF_METRIC_SIZE  12
194
195  static
196  const FT_Frame_Field  pcf_metric_header[] =
197  {
198#undef  FT_STRUCTURE
199#define FT_STRUCTURE  PCF_MetricRec
200
201    FT_FRAME_START( PCF_METRIC_SIZE ),
202      FT_FRAME_SHORT_LE( leftSideBearing ),
203      FT_FRAME_SHORT_LE( rightSideBearing ),
204      FT_FRAME_SHORT_LE( characterWidth ),
205      FT_FRAME_SHORT_LE( ascent ),
206      FT_FRAME_SHORT_LE( descent ),
207      FT_FRAME_SHORT_LE( attributes ),
208    FT_FRAME_END
209  };
210
211
212  static
213  const FT_Frame_Field  pcf_metric_msb_header[] =
214  {
215#undef  FT_STRUCTURE
216#define FT_STRUCTURE  PCF_MetricRec
217
218    FT_FRAME_START( PCF_METRIC_SIZE ),
219      FT_FRAME_SHORT( leftSideBearing ),
220      FT_FRAME_SHORT( rightSideBearing ),
221      FT_FRAME_SHORT( characterWidth ),
222      FT_FRAME_SHORT( ascent ),
223      FT_FRAME_SHORT( descent ),
224      FT_FRAME_SHORT( attributes ),
225    FT_FRAME_END
226  };
227
228
229#define PCF_COMPRESSED_METRIC_SIZE  5
230
231  static
232  const FT_Frame_Field  pcf_compressed_metric_header[] =
233  {
234#undef  FT_STRUCTURE
235#define FT_STRUCTURE  PCF_Compressed_MetricRec
236
237    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
238      FT_FRAME_BYTE( leftSideBearing ),
239      FT_FRAME_BYTE( rightSideBearing ),
240      FT_FRAME_BYTE( characterWidth ),
241      FT_FRAME_BYTE( ascent ),
242      FT_FRAME_BYTE( descent ),
243    FT_FRAME_END
244  };
245
246
247  static FT_Error
248  pcf_get_metric( FT_Stream   stream,
249                  FT_ULong    format,
250                  PCF_Metric  metric )
251  {
252    FT_Error  error = PCF_Err_Ok;
253
254
255    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
256    {
257      const FT_Frame_Field*  fields;
258
259
260      /* parsing normal metrics */
261      fields = PCF_BYTE_ORDER( format ) == MSBFirst
262               ? pcf_metric_msb_header
263               : pcf_metric_header;
264
265      /* the following sets `error' but doesn't return in case of failure */
266      (void)FT_STREAM_READ_FIELDS( fields, metric );
267    }
268    else
269    {
270      PCF_Compressed_MetricRec  compr;
271
272
273      /* parsing compressed metrics */
274      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
275        goto Exit;
276
277      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
278      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
279      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
280      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
281      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
282      metric->attributes       = 0;
283    }
284
285  Exit:
286    return error;
287  }
288
289
290  static FT_Error
291  pcf_seek_to_table_type( FT_Stream  stream,
292                          PCF_Table  tables,
293                          FT_Int     ntables,
294                          FT_ULong   type,
295                          FT_ULong  *aformat,
296                          FT_ULong  *asize )
297  {
298    FT_Error  error = PCF_Err_Invalid_File_Format;
299    FT_Int    i;
300
301
302    for ( i = 0; i < ntables; i++ )
303      if ( tables[i].type == type )
304      {
305        if ( stream->pos > tables[i].offset )
306        {
307          error = PCF_Err_Invalid_Stream_Skip;
308          goto Fail;
309        }
310
311        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
312        {
313          error = PCF_Err_Invalid_Stream_Skip;
314          goto Fail;
315        }
316
317        *asize   = tables[i].size;
318        *aformat = tables[i].format;
319
320        return PCF_Err_Ok;
321      }
322
323  Fail:
324    return error;
325  }
326
327
328  static FT_Bool
329  pcf_has_table_type( PCF_Table  tables,
330                      FT_Int     ntables,
331                      FT_ULong   type )
332  {
333    FT_Int  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;
402    FT_UInt            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\n", nprops ));
437
438    /* rough estimate */
439    if ( nprops > size / PCF_PROPERTY_SIZE )
440    {
441      error = PCF_Err_Invalid_Table;
442      goto Bail;
443    }
444
445    face->nprops = nprops;
446
447    if ( FT_NEW_ARRAY( props, nprops ) )
448      goto Bail;
449
450    for ( i = 0; i < nprops; i++ )
451    {
452      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
453      {
454        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
455          goto Bail;
456      }
457      else
458      {
459        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
460          goto Bail;
461      }
462    }
463
464    /* pad the property array                                            */
465    /*                                                                   */
466    /* clever here - nprops is the same as the number of odd-units read, */
467    /* as only isStringProp are odd length   (Keith Packard)             */
468    /*                                                                   */
469    if ( nprops & 3 )
470    {
471      i = 4 - ( nprops & 3 );
472      FT_Stream_Skip( stream, i );
473    }
474
475    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
476      (void)FT_READ_ULONG( string_size );
477    else
478      (void)FT_READ_ULONG_LE( string_size );
479    if ( error )
480      goto Bail;
481
482    FT_TRACE4(( "  string_size = %ld\n", string_size ));
483
484    /* rough estimate */
485    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
486    {
487      error = PCF_Err_Invalid_Table;
488      goto Bail;
489    }
490
491    if ( FT_NEW_ARRAY( strings, string_size ) )
492      goto Bail;
493
494    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
495    if ( error )
496      goto Bail;
497
498    if ( FT_NEW_ARRAY( properties, nprops ) )
499      goto Bail;
500
501    face->properties = properties;
502
503    for ( i = 0; i < nprops; i++ )
504    {
505      FT_Long  name_offset = props[i].name;
506
507
508      if ( ( name_offset < 0 )                     ||
509           ( (FT_ULong)name_offset > string_size ) )
510      {
511        error = PCF_Err_Invalid_Offset;
512        goto Bail;
513      }
514
515      if ( FT_NEW_ARRAY( properties[i].name,
516                         ft_strlen( strings + name_offset ) + 1 ) )
517        goto Bail;
518      ft_strcpy( properties[i].name, strings + name_offset );
519
520      FT_TRACE4(( "  %s:", properties[i].name ));
521
522      properties[i].isString = props[i].isString;
523
524      if ( props[i].isString )
525      {
526        FT_Long  value_offset = props[i].value;
527
528
529        if ( ( value_offset < 0 )                     ||
530             ( (FT_ULong)value_offset > string_size ) )
531        {
532          error = PCF_Err_Invalid_Offset;
533          goto Bail;
534        }
535
536        if ( FT_NEW_ARRAY( properties[i].value.atom,
537                           ft_strlen( strings + value_offset ) + 1 ) )
538          goto Bail;
539        ft_strcpy( properties[i].value.atom, strings + props[i].value );
540
541        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
542      }
543      else
544      {
545        properties[i].value.integer = props[i].value;
546
547        FT_TRACE4(( " %d\n", properties[i].value.integer ));
548      }
549    }
550
551    error = PCF_Err_Ok;
552   
553  Bail:
554    FT_FREE( props );
555    FT_FREE( strings );
556
557    return error;
558  }
559
560
561  static FT_Error
562  pcf_get_metrics( FT_Stream  stream,
563                   PCF_Face   face )
564  {
565    FT_Error    error    = PCF_Err_Ok;
566    FT_Memory   memory   = FT_FACE(face)->memory;
567    FT_ULong    format, size;
568    PCF_Metric  metrics  = 0;
569    FT_ULong    nmetrics, i;
570
571
572    error = pcf_seek_to_table_type( stream,
573                                    face->toc.tables,
574                                    face->toc.count,
575                                    PCF_METRICS,
576                                    &format,
577                                    &size );
578    if ( error )
579      return error;
580
581    if ( FT_READ_ULONG_LE( format ) )
582      goto Bail;
583
584    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
585         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
586      return PCF_Err_Invalid_File_Format;
587
588    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
589    {
590      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
591        (void)FT_READ_ULONG( nmetrics );
592      else
593        (void)FT_READ_ULONG_LE( nmetrics );
594    }
595    else
596    {
597      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
598        (void)FT_READ_USHORT( nmetrics );
599      else
600        (void)FT_READ_USHORT_LE( nmetrics );
601    }
602    if ( error )
603      return PCF_Err_Invalid_File_Format;
604
605    face->nmetrics = nmetrics;
606
607    FT_TRACE4(( "pcf_get_metrics:\n" ));
608
609    FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
610
611    /* rough estimate */
612    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
613    {
614      if ( nmetrics > size / PCF_METRIC_SIZE )
615        return PCF_Err_Invalid_Table;
616    }
617    else
618    {
619      if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
620        return PCF_Err_Invalid_Table;
621    }
622
623    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
624      return PCF_Err_Out_Of_Memory;
625
626    metrics = face->metrics;
627    for ( i = 0; i < nmetrics; i++ )
628    {
629      pcf_get_metric( stream, format, metrics + i );
630
631      metrics[i].bits = 0;
632
633      FT_TRACE5(( "  idx %d: width=%d, "
634                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
635                  i,
636                  ( metrics + i )->characterWidth,
637                  ( metrics + i )->leftSideBearing,
638                  ( metrics + i )->rightSideBearing,
639                  ( metrics + i )->ascent,
640                  ( metrics + i )->descent,
641                  ( metrics + i )->attributes ));
642
643      if ( error )
644        break;
645    }
646
647    if ( error )
648      FT_FREE( face->metrics );
649
650  Bail:
651    return error;
652  }
653
654
655  static FT_Error
656  pcf_get_bitmaps( FT_Stream  stream,
657                   PCF_Face   face )
658  {
659    FT_Error   error  = PCF_Err_Ok;
660    FT_Memory  memory = FT_FACE(face)->memory;
661    FT_Long*   offsets;
662    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
663    FT_ULong   format, size;
664    int        nbitmaps, i, sizebitmaps = 0;
665
666
667    error = pcf_seek_to_table_type( stream,
668                                    face->toc.tables,
669                                    face->toc.count,
670                                    PCF_BITMAPS,
671                                    &format,
672                                    &size );
673    if ( error )
674      return error;
675
676    error = FT_Stream_EnterFrame( stream, 8 );
677    if ( error )
678      return error;
679
680    format = FT_GET_ULONG_LE();
681    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
682      nbitmaps  = FT_GET_ULONG();
683    else
684      nbitmaps  = FT_GET_ULONG_LE();
685
686    FT_Stream_ExitFrame( stream );
687
688    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
689      return PCF_Err_Invalid_File_Format;
690
691    FT_TRACE4(( "pcf_get_bitmaps:\n" ));
692
693    FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
694
695    if ( nbitmaps != face->nmetrics )
696      return PCF_Err_Invalid_File_Format;
697
698    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
699      return error;
700
701    for ( i = 0; i < nbitmaps; i++ )
702    {
703      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
704        (void)FT_READ_LONG( offsets[i] );
705      else
706        (void)FT_READ_LONG_LE( offsets[i] );
707
708      FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
709                  i, offsets[i], offsets[i] ));
710    }
711    if ( error )
712      goto Bail;
713
714    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
715    {
716      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
717        (void)FT_READ_LONG( bitmapSizes[i] );
718      else
719        (void)FT_READ_LONG_LE( bitmapSizes[i] );
720      if ( error )
721        goto Bail;
722
723      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
724
725      FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
726    }
727
728    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
729                nbitmaps,
730                PCF_GLYPH_PAD_INDEX( format ) ));
731    FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
732
733    FT_UNUSED( sizebitmaps );       /* only used for debugging */
734
735    for ( i = 0; i < nbitmaps; i++ )
736    {
737      /* rough estimate */
738      if ( ( offsets[i] < 0 )              ||
739           ( (FT_ULong)offsets[i] > size ) )
740      {
741        FT_ERROR(( "pcf_get_bitmaps:"));
742        FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i ));
743      }
744      else
745        face->metrics[i].bits = stream->pos + offsets[i];
746    }
747
748    face->bitmapsFormat = format;
749
750  Bail:
751    FT_FREE( offsets );
752    return error;
753  }
754
755
756  static FT_Error
757  pcf_get_encodings( FT_Stream  stream,
758                     PCF_Face   face )
759  {
760    FT_Error      error  = PCF_Err_Ok;
761    FT_Memory     memory = FT_FACE(face)->memory;
762    FT_ULong      format, size;
763    int           firstCol, lastCol;
764    int           firstRow, lastRow;
765    int           nencoding, encodingOffset;
766    int           i, j;
767    PCF_Encoding  tmpEncoding, encoding = 0;
768
769
770    error = pcf_seek_to_table_type( stream,
771                                    face->toc.tables,
772                                    face->toc.count,
773                                    PCF_BDF_ENCODINGS,
774                                    &format,
775                                    &size );
776    if ( error )
777      return error;
778
779    error = FT_Stream_EnterFrame( stream, 14 );
780    if ( error )
781      return error;
782
783    format = FT_GET_ULONG_LE();
784
785    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
786    {
787      firstCol          = FT_GET_SHORT();
788      lastCol           = FT_GET_SHORT();
789      firstRow          = FT_GET_SHORT();
790      lastRow           = FT_GET_SHORT();
791      face->defaultChar = FT_GET_SHORT();
792    }
793    else
794    {
795      firstCol          = FT_GET_SHORT_LE();
796      lastCol           = FT_GET_SHORT_LE();
797      firstRow          = FT_GET_SHORT_LE();
798      lastRow           = FT_GET_SHORT_LE();
799      face->defaultChar = FT_GET_SHORT_LE();
800    }
801
802    FT_Stream_ExitFrame( stream );
803
804    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
805      return PCF_Err_Invalid_File_Format;
806
807    FT_TRACE4(( "pdf_get_encodings:\n" ));
808
809    FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
810                firstCol, lastCol, firstRow, lastRow ));
811
812    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
813
814    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
815      return PCF_Err_Out_Of_Memory;
816
817    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
818    if ( error )
819      goto Bail;
820
821    for ( i = 0, j = 0 ; i < nencoding; i++ )
822    {
823      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
824        encodingOffset = FT_GET_SHORT();
825      else
826        encodingOffset = FT_GET_SHORT_LE();
827
828      if ( encodingOffset != -1 )
829      {
830        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
831                                 firstRow ) * 256 ) +
832                               ( ( i % ( lastCol - firstCol + 1 ) ) +
833                                 firstCol );
834
835        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
836
837        FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
838                    tmpEncoding[j].enc, tmpEncoding[j].enc,
839                    tmpEncoding[j].glyph ));
840
841        j++;
842      }
843    }
844    FT_Stream_ExitFrame( stream );
845
846    if ( FT_NEW_ARRAY( encoding, j ) )
847      goto Bail;
848
849    for ( i = 0; i < j; i++ )
850    {
851      encoding[i].enc   = tmpEncoding[i].enc;
852      encoding[i].glyph = tmpEncoding[i].glyph;
853    }
854
855    face->nencodings = j;
856    face->encodings  = encoding;
857    FT_FREE( tmpEncoding );
858
859    return error;
860
861  Bail:
862    FT_FREE( encoding );
863    FT_FREE( tmpEncoding );
864    return error;
865  }
866
867
868  static
869  const FT_Frame_Field  pcf_accel_header[] =
870  {
871#undef  FT_STRUCTURE
872#define FT_STRUCTURE  PCF_AccelRec
873
874    FT_FRAME_START( 20 ),
875      FT_FRAME_BYTE      ( noOverlap ),
876      FT_FRAME_BYTE      ( constantMetrics ),
877      FT_FRAME_BYTE      ( terminalFont ),
878      FT_FRAME_BYTE      ( constantWidth ),
879      FT_FRAME_BYTE      ( inkInside ),
880      FT_FRAME_BYTE      ( inkMetrics ),
881      FT_FRAME_BYTE      ( drawDirection ),
882      FT_FRAME_SKIP_BYTES( 1 ),
883      FT_FRAME_LONG_LE   ( fontAscent ),
884      FT_FRAME_LONG_LE   ( fontDescent ),
885      FT_FRAME_LONG_LE   ( maxOverlap ),
886    FT_FRAME_END
887  };
888
889
890  static
891  const FT_Frame_Field  pcf_accel_msb_header[] =
892  {
893#undef  FT_STRUCTURE
894#define FT_STRUCTURE  PCF_AccelRec
895
896    FT_FRAME_START( 20 ),
897      FT_FRAME_BYTE      ( noOverlap ),
898      FT_FRAME_BYTE      ( constantMetrics ),
899      FT_FRAME_BYTE      ( terminalFont ),
900      FT_FRAME_BYTE      ( constantWidth ),
901      FT_FRAME_BYTE      ( inkInside ),
902      FT_FRAME_BYTE      ( inkMetrics ),
903      FT_FRAME_BYTE      ( drawDirection ),
904      FT_FRAME_SKIP_BYTES( 1 ),
905      FT_FRAME_LONG      ( fontAscent ),
906      FT_FRAME_LONG      ( fontDescent ),
907      FT_FRAME_LONG      ( maxOverlap ),
908    FT_FRAME_END
909  };
910
911
912  static FT_Error
913  pcf_get_accel( FT_Stream  stream,
914                 PCF_Face   face,
915                 FT_ULong   type )
916  {
917    FT_ULong   format, size;
918    FT_Error   error = PCF_Err_Ok;
919    PCF_Accel  accel = &face->accel;
920
921
922    error = pcf_seek_to_table_type( stream,
923                                    face->toc.tables,
924                                    face->toc.count,
925                                    type,
926                                    &format,
927                                    &size );
928    if ( error )
929      goto Bail;
930
931    if ( FT_READ_ULONG_LE( format ) )
932      goto Bail;
933
934    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
935         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
936      goto Bail;
937
938    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
939    {
940      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
941        goto Bail;
942    }
943    else
944    {
945      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
946        goto Bail;
947    }
948
949    error = pcf_get_metric( stream,
950                            format & ( ~PCF_FORMAT_MASK ),
951                            &(accel->minbounds) );
952    if ( error )
953      goto Bail;
954
955    error = pcf_get_metric( stream,
956                            format & ( ~PCF_FORMAT_MASK ),
957                            &(accel->maxbounds) );
958    if ( error )
959      goto Bail;
960
961    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
962    {
963      error = pcf_get_metric( stream,
964                              format & ( ~PCF_FORMAT_MASK ),
965                              &(accel->ink_minbounds) );
966      if ( error )
967        goto Bail;
968
969      error = pcf_get_metric( stream,
970                              format & ( ~PCF_FORMAT_MASK ),
971                              &(accel->ink_maxbounds) );
972      if ( error )
973        goto Bail;
974    }
975    else
976    {
977      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
978      accel->ink_maxbounds = accel->maxbounds;
979    }
980
981  Bail:
982    return error;
983  }
984
985
986  static FT_Error
987  pcf_interpret_style( PCF_Face  pcf )
988  {
989    FT_Error   error  = PCF_Err_Ok;
990    FT_Face    face   = FT_FACE( pcf );
991    FT_Memory  memory = face->memory;
992
993    PCF_Property  prop;
994
995    char  *istr = NULL, *bstr = NULL;
996    char  *sstr = NULL, *astr = NULL;
997
998    int  parts = 0, len = 0;
999
1000
1001    face->style_flags = 0;
1002
1003    prop = pcf_find_property( pcf, "SLANT" );
1004    if ( prop && prop->isString                                       &&
1005         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1006           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1007    {
1008      face->style_flags |= FT_STYLE_FLAG_ITALIC;
1009      istr = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' )
1010               ? (char *)"Oblique"
1011               : (char *)"Italic";
1012      len += ft_strlen( istr );
1013      parts++;
1014    }
1015
1016    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1017    if ( prop && prop->isString                                       &&
1018         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1019    {
1020      face->style_flags |= FT_STYLE_FLAG_BOLD;
1021      bstr = (char *)"Bold";
1022      len += ft_strlen( bstr );
1023      parts++;
1024    }
1025
1026    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1027    if ( prop && prop->isString                                        &&
1028         *(prop->value.atom)                                           &&
1029         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1030    {
1031      sstr = (char *)(prop->value.atom);
1032      len += ft_strlen( sstr );
1033      parts++;
1034    }
1035
1036    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1037    if ( prop && prop->isString                                        &&
1038         *(prop->value.atom)                                           &&
1039         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1040    {
1041      astr = (char *)(prop->value.atom);
1042      len += ft_strlen( astr );
1043      parts++;
1044    }
1045
1046    if ( !parts || !len )
1047    {
1048      if ( FT_ALLOC( face->style_name, 8 ) )
1049        return error;
1050      ft_strcpy( face->style_name, "Regular" );
1051      face->style_name[7] = '\0';
1052    }
1053    else
1054    {
1055      char          *style, *s;
1056      unsigned int  i;
1057
1058
1059      if ( FT_ALLOC( style, len + parts ) )
1060        return error;
1061
1062      s = style;
1063
1064      if ( astr )
1065      {
1066        ft_strcpy( s, astr );
1067        for ( i = 0; i < ft_strlen( astr ); i++, s++ )
1068          if ( *s == ' ' )
1069            *s = '-';                     /* replace spaces with dashes */
1070        *(s++) = ' ';
1071      }
1072      if ( bstr )
1073      {
1074        ft_strcpy( s, bstr );
1075        s += ft_strlen( bstr );
1076        *(s++) = ' ';
1077      }
1078      if ( istr )
1079      {
1080        ft_strcpy( s, istr );
1081        s += ft_strlen( istr );
1082        *(s++) = ' ';
1083      }
1084      if ( sstr )
1085      {
1086        ft_strcpy( s, sstr );
1087        for ( i = 0; i < ft_strlen( sstr ); i++, s++ )
1088          if ( *s == ' ' )
1089            *s = '-';                     /* replace spaces with dashes */
1090        *(s++) = ' ';
1091      }
1092      *(--s) = '\0';        /* overwrite last ' ', terminate the string */
1093
1094      face->style_name = style;                     /* allocated string */
1095    }
1096
1097    return error;
1098  }
1099
1100
1101  FT_LOCAL_DEF( FT_Error )
1102  pcf_load_font( FT_Stream  stream,
1103                 PCF_Face   face )
1104  {
1105    FT_Error   error  = PCF_Err_Ok;
1106    FT_Memory  memory = FT_FACE(face)->memory;
1107    FT_Bool    hasBDFAccelerators;
1108
1109
1110    error = pcf_read_TOC( stream, face );
1111    if ( error )
1112      goto Exit;
1113
1114    error = pcf_get_properties( stream, face );
1115    if ( error )
1116      goto Exit;
1117
1118    /* Use the old accelerators if no BDF accelerators are in the file. */
1119    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1120                                             face->toc.count,
1121                                             PCF_BDF_ACCELERATORS );
1122    if ( !hasBDFAccelerators )
1123    {
1124      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1125      if ( error )
1126        goto Exit;
1127    }
1128
1129    /* metrics */
1130    error = pcf_get_metrics( stream, face );
1131    if ( error )
1132      goto Exit;
1133
1134    /* bitmaps */
1135    error = pcf_get_bitmaps( stream, face );
1136    if ( error )
1137      goto Exit;
1138
1139    /* encodings */
1140    error = pcf_get_encodings( stream, face );
1141    if ( error )
1142      goto Exit;
1143
1144    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1145    if ( hasBDFAccelerators )
1146    {
1147      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1148      if ( error )
1149        goto Exit;
1150    }
1151
1152    /* XXX: TO DO: inkmetrics and glyph_names are missing */
1153
1154    /* now construct the face object */
1155    {
1156      FT_Face       root = FT_FACE( face );
1157      PCF_Property  prop;
1158
1159
1160      root->num_faces  = 1;
1161      root->face_index = 0;
1162      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1163                         FT_FACE_FLAG_HORIZONTAL  |
1164                         FT_FACE_FLAG_FAST_GLYPHS;
1165
1166      if ( face->accel.constantWidth )
1167        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1168
1169      if ( ( error = pcf_interpret_style( face ) ) != 0 )
1170         goto Exit;
1171
1172      prop = pcf_find_property( face, "FAMILY_NAME" );
1173      if ( prop && prop->isString )
1174      {
1175        int  l = ft_strlen( prop->value.atom ) + 1;
1176
1177
1178        if ( FT_NEW_ARRAY( root->family_name, l ) )
1179          goto Exit;
1180        ft_strcpy( root->family_name, prop->value.atom );
1181      }
1182      else
1183        root->family_name = NULL;
1184
1185      /*
1186       * Note: We shift all glyph indices by +1 since we must
1187       * respect the convention that glyph 0 always corresponds
1188       * to the `missing glyph'.
1189       *
1190       * This implies bumping the number of `available' glyphs by 1.
1191       */
1192      root->num_glyphs = face->nmetrics + 1;
1193
1194      root->num_fixed_sizes = 1;
1195      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1196        goto Exit;
1197
1198      {
1199        FT_Bitmap_Size*  bsize = root->available_sizes;
1200        FT_Short         resolution_x = 0, resolution_y = 0;
1201
1202
1203        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1204
1205#if 0
1206        bsize->height = face->accel.maxbounds.ascent << 6;
1207#endif
1208        bsize->height = (FT_Short)( face->accel.fontAscent +
1209                                    face->accel.fontDescent );
1210
1211        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1212        if ( prop )
1213          bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 );
1214        else
1215          bsize->width = (FT_Short)( bsize->height * 2/3 );
1216
1217        prop = pcf_find_property( face, "POINT_SIZE" );
1218        if ( prop )
1219          /* convert from 722.7 decipoints to 72 points per inch */
1220          bsize->size =
1221            (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L );
1222
1223        prop = pcf_find_property( face, "PIXEL_SIZE" );
1224        if ( prop )
1225          bsize->y_ppem = (FT_Short)prop->value.integer << 6;
1226
1227        prop = pcf_find_property( face, "RESOLUTION_X" );
1228        if ( prop )
1229          resolution_x = (FT_Short)prop->value.integer;
1230
1231        prop = pcf_find_property( face, "RESOLUTION_Y" );
1232        if ( prop )
1233          resolution_y = (FT_Short)prop->value.integer;
1234
1235        if ( bsize->y_ppem == 0 )
1236        {
1237          bsize->y_ppem = bsize->size;
1238          if ( resolution_y )
1239            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1240        }
1241        if ( resolution_x && resolution_y )
1242          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1243        else
1244          bsize->x_ppem = bsize->y_ppem;
1245      }
1246
1247      /* set up charset */
1248      {
1249        PCF_Property  charset_registry = 0, charset_encoding = 0;
1250
1251
1252        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1253        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1254
1255        if ( charset_registry && charset_registry->isString &&
1256             charset_encoding && charset_encoding->isString )
1257        {
1258          if ( FT_NEW_ARRAY( face->charset_encoding,
1259                             ft_strlen( charset_encoding->value.atom ) + 1 ) )
1260            goto Exit;
1261
1262          if ( FT_NEW_ARRAY( face->charset_registry,
1263                             ft_strlen( charset_registry->value.atom ) + 1 ) )
1264            goto Exit;
1265
1266          ft_strcpy( face->charset_registry, charset_registry->value.atom );
1267          ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
1268        }
1269      }
1270    }
1271
1272  Exit:
1273    if ( error )
1274    {
1275      /* This is done to respect the behaviour of the original */
1276      /* PCF font driver.                                      */
1277      error = PCF_Err_Invalid_File_Format;
1278    }
1279
1280    return error;
1281  }
1282
1283
1284/* END */
Note: See TracBrowser for help on using the repository browser.