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

Last change on this file since 269 was 269, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.9

File size: 34.2 KB
Line 
1/*  pcfread.c
2
3    FreeType font driver for pcf fonts
4
5  Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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#ifdef 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#ifdef 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    *asize = 0;
325    return error;
326  }
327
328
329  static FT_Bool
330  pcf_has_table_type( PCF_Table  tables,
331                      FT_Int     ntables,
332                      FT_ULong   type )
333  {
334    FT_Int  i;
335
336
337    for ( i = 0; i < ntables; i++ )
338      if ( tables[i].type == type )
339        return TRUE;
340
341    return FALSE;
342  }
343
344
345#define PCF_PROPERTY_SIZE  9
346
347  static
348  const FT_Frame_Field  pcf_property_header[] =
349  {
350#undef  FT_STRUCTURE
351#define FT_STRUCTURE  PCF_ParsePropertyRec
352
353    FT_FRAME_START( PCF_PROPERTY_SIZE ),
354      FT_FRAME_LONG_LE( name ),
355      FT_FRAME_BYTE   ( isString ),
356      FT_FRAME_LONG_LE( value ),
357    FT_FRAME_END
358  };
359
360
361  static
362  const FT_Frame_Field  pcf_property_msb_header[] =
363  {
364#undef  FT_STRUCTURE
365#define FT_STRUCTURE  PCF_ParsePropertyRec
366
367    FT_FRAME_START( PCF_PROPERTY_SIZE ),
368      FT_FRAME_LONG( name ),
369      FT_FRAME_BYTE( isString ),
370      FT_FRAME_LONG( value ),
371    FT_FRAME_END
372  };
373
374
375  FT_LOCAL_DEF( PCF_Property )
376  pcf_find_property( PCF_Face          face,
377                     const FT_String*  prop )
378  {
379    PCF_Property  properties = face->properties;
380    FT_Bool       found      = 0;
381    int           i;
382
383
384    for ( i = 0 ; i < face->nprops && !found; i++ )
385    {
386      if ( !ft_strcmp( properties[i].name, prop ) )
387        found = 1;
388    }
389
390    if ( found )
391      return properties + i - 1;
392    else
393      return NULL;
394  }
395
396
397  static FT_Error
398  pcf_get_properties( FT_Stream  stream,
399                      PCF_Face   face )
400  {
401    PCF_ParseProperty  props      = 0;
402    PCF_Property       properties;
403    FT_UInt            nprops, i;
404    FT_ULong           format, size;
405    FT_Error           error;
406    FT_Memory          memory     = FT_FACE(face)->memory;
407    FT_ULong           string_size;
408    FT_String*         strings    = 0;
409
410
411    error = pcf_seek_to_table_type( stream,
412                                    face->toc.tables,
413                                    face->toc.count,
414                                    PCF_PROPERTIES,
415                                    &format,
416                                    &size );
417    if ( error )
418      goto Bail;
419
420    if ( FT_READ_ULONG_LE( format ) )
421      goto Bail;
422
423    FT_TRACE4(( "pcf_get_properties:\n" ));
424
425    FT_TRACE4(( "  format = %ld\n", format ));
426
427    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
428      goto Bail;
429
430    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
431      (void)FT_READ_ULONG( nprops );
432    else
433      (void)FT_READ_ULONG_LE( nprops );
434    if ( error )
435      goto Bail;
436
437    FT_TRACE4(( "  nprop = %d\n", nprops ));
438
439    /* rough estimate */
440    if ( nprops > size / PCF_PROPERTY_SIZE )
441    {
442      error = PCF_Err_Invalid_Table;
443      goto Bail;
444    }
445
446    face->nprops = nprops;
447
448    if ( FT_NEW_ARRAY( props, nprops ) )
449      goto Bail;
450
451    for ( i = 0; i < nprops; i++ )
452    {
453      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
454      {
455        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
456          goto Bail;
457      }
458      else
459      {
460        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
461          goto Bail;
462      }
463    }
464
465    /* pad the property array                                            */
466    /*                                                                   */
467    /* clever here - nprops is the same as the number of odd-units read, */
468    /* as only isStringProp are odd length   (Keith Packard)             */
469    /*                                                                   */
470    if ( nprops & 3 )
471    {
472      i = 4 - ( nprops & 3 );
473      if ( FT_STREAM_SKIP( i ) )
474      {
475        error = PCF_Err_Invalid_Stream_Skip;
476        goto Bail;
477      }
478    }
479
480    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
481      (void)FT_READ_ULONG( string_size );
482    else
483      (void)FT_READ_ULONG_LE( string_size );
484    if ( error )
485      goto Bail;
486
487    FT_TRACE4(( "  string_size = %ld\n", string_size ));
488
489    /* rough estimate */
490    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
491    {
492      error = PCF_Err_Invalid_Table;
493      goto Bail;
494    }
495
496    if ( FT_NEW_ARRAY( strings, string_size ) )
497      goto Bail;
498
499    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
500    if ( error )
501      goto Bail;
502
503    if ( FT_NEW_ARRAY( properties, nprops ) )
504      goto Bail;
505
506    face->properties = properties;
507
508    for ( i = 0; i < nprops; i++ )
509    {
510      FT_Long  name_offset = props[i].name;
511
512
513      if ( ( name_offset < 0 )                     ||
514           ( (FT_ULong)name_offset > string_size ) )
515      {
516        error = PCF_Err_Invalid_Offset;
517        goto Bail;
518      }
519
520      if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
521        goto Bail;
522
523      FT_TRACE4(( "  %s:", properties[i].name ));
524
525      properties[i].isString = props[i].isString;
526
527      if ( props[i].isString )
528      {
529        FT_Long  value_offset = props[i].value;
530
531
532        if ( ( value_offset < 0 )                     ||
533             ( (FT_ULong)value_offset > string_size ) )
534        {
535          error = PCF_Err_Invalid_Offset;
536          goto Bail;
537        }
538
539        if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
540          goto Bail;
541
542        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
543      }
544      else
545      {
546        properties[i].value.integer = props[i].value;
547
548        FT_TRACE4(( " %d\n", properties[i].value.integer ));
549      }
550    }
551
552    error = PCF_Err_Ok;
553
554  Bail:
555    FT_FREE( props );
556    FT_FREE( strings );
557
558    return error;
559  }
560
561
562  static FT_Error
563  pcf_get_metrics( FT_Stream  stream,
564                   PCF_Face   face )
565  {
566    FT_Error    error    = PCF_Err_Ok;
567    FT_Memory   memory   = FT_FACE(face)->memory;
568    FT_ULong    format, size;
569    PCF_Metric  metrics  = 0;
570    FT_ULong    nmetrics, i;
571
572
573    error = pcf_seek_to_table_type( stream,
574                                    face->toc.tables,
575                                    face->toc.count,
576                                    PCF_METRICS,
577                                    &format,
578                                    &size );
579    if ( error )
580      return error;
581
582    if ( FT_READ_ULONG_LE( format ) )
583      goto Bail;
584
585    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
586         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
587      return PCF_Err_Invalid_File_Format;
588
589    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
590    {
591      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
592        (void)FT_READ_ULONG( nmetrics );
593      else
594        (void)FT_READ_ULONG_LE( nmetrics );
595    }
596    else
597    {
598      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
599        (void)FT_READ_USHORT( nmetrics );
600      else
601        (void)FT_READ_USHORT_LE( nmetrics );
602    }
603    if ( error )
604      return PCF_Err_Invalid_File_Format;
605
606    face->nmetrics = nmetrics;
607
608    FT_TRACE4(( "pcf_get_metrics:\n" ));
609
610    FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
611
612    /* rough estimate */
613    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
614    {
615      if ( nmetrics > size / PCF_METRIC_SIZE )
616        return PCF_Err_Invalid_Table;
617    }
618    else
619    {
620      if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
621        return PCF_Err_Invalid_Table;
622    }
623
624    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
625      return PCF_Err_Out_Of_Memory;
626
627    metrics = face->metrics;
628    for ( i = 0; i < nmetrics; i++ )
629    {
630      error = pcf_get_metric( stream, format, metrics + i );
631
632      metrics[i].bits = 0;
633
634      FT_TRACE5(( "  idx %d: width=%d, "
635                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
636                  i,
637                  ( metrics + i )->characterWidth,
638                  ( metrics + i )->leftSideBearing,
639                  ( metrics + i )->rightSideBearing,
640                  ( metrics + i )->ascent,
641                  ( metrics + i )->descent,
642                  ( metrics + i )->attributes ));
643
644      if ( error )
645        break;
646    }
647
648    if ( error )
649      FT_FREE( face->metrics );
650
651  Bail:
652    return error;
653  }
654
655
656  static FT_Error
657  pcf_get_bitmaps( FT_Stream  stream,
658                   PCF_Face   face )
659  {
660    FT_Error   error  = PCF_Err_Ok;
661    FT_Memory  memory = FT_FACE(face)->memory;
662    FT_Long*   offsets;
663    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
664    FT_ULong   format, size;
665    int        nbitmaps, i, sizebitmaps = 0;
666
667
668    error = pcf_seek_to_table_type( stream,
669                                    face->toc.tables,
670                                    face->toc.count,
671                                    PCF_BITMAPS,
672                                    &format,
673                                    &size );
674    if ( error )
675      return error;
676
677    error = FT_Stream_EnterFrame( stream, 8 );
678    if ( error )
679      return error;
680
681    format = FT_GET_ULONG_LE();
682    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
683      nbitmaps  = FT_GET_ULONG();
684    else
685      nbitmaps  = FT_GET_ULONG_LE();
686
687    FT_Stream_ExitFrame( stream );
688
689    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
690      return PCF_Err_Invalid_File_Format;
691
692    FT_TRACE4(( "pcf_get_bitmaps:\n" ));
693
694    FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
695
696    if ( nbitmaps != face->nmetrics )
697      return PCF_Err_Invalid_File_Format;
698
699    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
700      return error;
701
702    for ( i = 0; i < nbitmaps; i++ )
703    {
704      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
705        (void)FT_READ_LONG( offsets[i] );
706      else
707        (void)FT_READ_LONG_LE( offsets[i] );
708
709      FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
710                  i, offsets[i], offsets[i] ));
711    }
712    if ( error )
713      goto Bail;
714
715    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
716    {
717      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
718        (void)FT_READ_LONG( bitmapSizes[i] );
719      else
720        (void)FT_READ_LONG_LE( bitmapSizes[i] );
721      if ( error )
722        goto Bail;
723
724      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
725
726      FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
727    }
728
729    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
730                nbitmaps,
731                PCF_GLYPH_PAD_INDEX( format ) ));
732    FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
733
734    FT_UNUSED( sizebitmaps );       /* only used for debugging */
735
736    for ( i = 0; i < nbitmaps; i++ )
737    {
738      /* rough estimate */
739      if ( ( offsets[i] < 0 )              ||
740           ( (FT_ULong)offsets[i] > size ) )
741      {
742        FT_ERROR(( "pcf_get_bitmaps:"));
743        FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i ));
744      }
745      else
746        face->metrics[i].bits = stream->pos + offsets[i];
747    }
748
749    face->bitmapsFormat = format;
750
751  Bail:
752    FT_FREE( offsets );
753    return error;
754  }
755
756
757  static FT_Error
758  pcf_get_encodings( FT_Stream  stream,
759                     PCF_Face   face )
760  {
761    FT_Error      error  = PCF_Err_Ok;
762    FT_Memory     memory = FT_FACE(face)->memory;
763    FT_ULong      format, size;
764    int           firstCol, lastCol;
765    int           firstRow, lastRow;
766    int           nencoding, encodingOffset;
767    int           i, j;
768    PCF_Encoding  tmpEncoding, encoding = 0;
769
770
771    error = pcf_seek_to_table_type( stream,
772                                    face->toc.tables,
773                                    face->toc.count,
774                                    PCF_BDF_ENCODINGS,
775                                    &format,
776                                    &size );
777    if ( error )
778      return error;
779
780    error = FT_Stream_EnterFrame( stream, 14 );
781    if ( error )
782      return error;
783
784    format = FT_GET_ULONG_LE();
785
786    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
787    {
788      firstCol          = FT_GET_SHORT();
789      lastCol           = FT_GET_SHORT();
790      firstRow          = FT_GET_SHORT();
791      lastRow           = FT_GET_SHORT();
792      face->defaultChar = FT_GET_SHORT();
793    }
794    else
795    {
796      firstCol          = FT_GET_SHORT_LE();
797      lastCol           = FT_GET_SHORT_LE();
798      firstRow          = FT_GET_SHORT_LE();
799      lastRow           = FT_GET_SHORT_LE();
800      face->defaultChar = FT_GET_SHORT_LE();
801    }
802
803    FT_Stream_ExitFrame( stream );
804
805    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
806      return PCF_Err_Invalid_File_Format;
807
808    FT_TRACE4(( "pdf_get_encodings:\n" ));
809
810    FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
811                firstCol, lastCol, firstRow, lastRow ));
812
813    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
814
815    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
816      return PCF_Err_Out_Of_Memory;
817
818    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
819    if ( error )
820      goto Bail;
821
822    for ( i = 0, j = 0 ; i < nencoding; i++ )
823    {
824      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
825        encodingOffset = FT_GET_SHORT();
826      else
827        encodingOffset = FT_GET_SHORT_LE();
828
829      if ( encodingOffset != -1 )
830      {
831        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
832                                 firstRow ) * 256 ) +
833                               ( ( i % ( lastCol - firstCol + 1 ) ) +
834                                 firstCol );
835
836        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
837
838        FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
839                    tmpEncoding[j].enc, tmpEncoding[j].enc,
840                    tmpEncoding[j].glyph ));
841
842        j++;
843      }
844    }
845    FT_Stream_ExitFrame( stream );
846
847    if ( FT_NEW_ARRAY( encoding, j ) )
848      goto Bail;
849
850    for ( i = 0; i < j; i++ )
851    {
852      encoding[i].enc   = tmpEncoding[i].enc;
853      encoding[i].glyph = tmpEncoding[i].glyph;
854    }
855
856    face->nencodings = j;
857    face->encodings  = encoding;
858    FT_FREE( tmpEncoding );
859
860    return error;
861
862  Bail:
863    FT_FREE( encoding );
864    FT_FREE( tmpEncoding );
865    return error;
866  }
867
868
869  static
870  const FT_Frame_Field  pcf_accel_header[] =
871  {
872#undef  FT_STRUCTURE
873#define FT_STRUCTURE  PCF_AccelRec
874
875    FT_FRAME_START( 20 ),
876      FT_FRAME_BYTE      ( noOverlap ),
877      FT_FRAME_BYTE      ( constantMetrics ),
878      FT_FRAME_BYTE      ( terminalFont ),
879      FT_FRAME_BYTE      ( constantWidth ),
880      FT_FRAME_BYTE      ( inkInside ),
881      FT_FRAME_BYTE      ( inkMetrics ),
882      FT_FRAME_BYTE      ( drawDirection ),
883      FT_FRAME_SKIP_BYTES( 1 ),
884      FT_FRAME_LONG_LE   ( fontAscent ),
885      FT_FRAME_LONG_LE   ( fontDescent ),
886      FT_FRAME_LONG_LE   ( maxOverlap ),
887    FT_FRAME_END
888  };
889
890
891  static
892  const FT_Frame_Field  pcf_accel_msb_header[] =
893  {
894#undef  FT_STRUCTURE
895#define FT_STRUCTURE  PCF_AccelRec
896
897    FT_FRAME_START( 20 ),
898      FT_FRAME_BYTE      ( noOverlap ),
899      FT_FRAME_BYTE      ( constantMetrics ),
900      FT_FRAME_BYTE      ( terminalFont ),
901      FT_FRAME_BYTE      ( constantWidth ),
902      FT_FRAME_BYTE      ( inkInside ),
903      FT_FRAME_BYTE      ( inkMetrics ),
904      FT_FRAME_BYTE      ( drawDirection ),
905      FT_FRAME_SKIP_BYTES( 1 ),
906      FT_FRAME_LONG      ( fontAscent ),
907      FT_FRAME_LONG      ( fontDescent ),
908      FT_FRAME_LONG      ( maxOverlap ),
909    FT_FRAME_END
910  };
911
912
913  static FT_Error
914  pcf_get_accel( FT_Stream  stream,
915                 PCF_Face   face,
916                 FT_ULong   type )
917  {
918    FT_ULong   format, size;
919    FT_Error   error = PCF_Err_Ok;
920    PCF_Accel  accel = &face->accel;
921
922
923    error = pcf_seek_to_table_type( stream,
924                                    face->toc.tables,
925                                    face->toc.count,
926                                    type,
927                                    &format,
928                                    &size );
929    if ( error )
930      goto Bail;
931
932    if ( FT_READ_ULONG_LE( format ) )
933      goto Bail;
934
935    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
936         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
937      goto Bail;
938
939    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
940    {
941      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
942        goto Bail;
943    }
944    else
945    {
946      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
947        goto Bail;
948    }
949
950    error = pcf_get_metric( stream,
951                            format & ( ~PCF_FORMAT_MASK ),
952                            &(accel->minbounds) );
953    if ( error )
954      goto Bail;
955
956    error = pcf_get_metric( stream,
957                            format & ( ~PCF_FORMAT_MASK ),
958                            &(accel->maxbounds) );
959    if ( error )
960      goto Bail;
961
962    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
963    {
964      error = pcf_get_metric( stream,
965                              format & ( ~PCF_FORMAT_MASK ),
966                              &(accel->ink_minbounds) );
967      if ( error )
968        goto Bail;
969
970      error = pcf_get_metric( stream,
971                              format & ( ~PCF_FORMAT_MASK ),
972                              &(accel->ink_maxbounds) );
973      if ( error )
974        goto Bail;
975    }
976    else
977    {
978      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
979      accel->ink_maxbounds = accel->maxbounds;
980    }
981
982  Bail:
983    return error;
984  }
985
986
987  static FT_Error
988  pcf_interpret_style( PCF_Face  pcf )
989  {
990    FT_Error   error  = PCF_Err_Ok;
991    FT_Face    face   = FT_FACE( pcf );
992    FT_Memory  memory = face->memory;
993
994    PCF_Property  prop;
995
996    int    nn, len;
997    char*  strings[4] = { NULL, NULL, NULL, NULL };
998    int    lengths[4];
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      strings[2] = ( *(prop->value.atom) == 'O' ||
1010                     *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1011                                                  : (char *)"Italic";
1012    }
1013
1014    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1015    if ( prop && prop->isString                                       &&
1016         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1017    {
1018      face->style_flags |= FT_STYLE_FLAG_BOLD;
1019      strings[1] = (char *)"Bold";
1020    }
1021
1022    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1023    if ( prop && prop->isString                                        &&
1024         *(prop->value.atom)                                           &&
1025         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1026      strings[3] = (char *)(prop->value.atom);
1027
1028    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1029    if ( prop && prop->isString                                        &&
1030         *(prop->value.atom)                                           &&
1031         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1032      strings[0] = (char *)(prop->value.atom);
1033
1034    for ( len = 0, nn = 0; nn < 4; nn++ )
1035    {
1036      lengths[nn] = 0;
1037      if ( strings[nn] )
1038      {
1039        lengths[nn] = ft_strlen( strings[nn] );
1040        len        += lengths[nn] + 1;
1041      }
1042    }
1043
1044    if ( len == 0 )
1045    {
1046      strings[0] = (char *)"Regular";
1047      lengths[0] = ft_strlen( strings[0] );
1048      len        = lengths[0] + 1;
1049    }
1050
1051    {
1052      char*  s;
1053
1054
1055      if ( FT_ALLOC( face->style_name, len ) )
1056        return error;
1057
1058      s = face->style_name;
1059
1060      for ( nn = 0; nn < 4; nn++ )
1061      {
1062        char*  src = strings[nn];
1063
1064
1065        len = lengths[nn];
1066
1067        if ( src == NULL )
1068          continue;
1069
1070        /* separate elements with a space */
1071        if ( s != face->style_name )
1072          *s++ = ' ';
1073
1074        ft_memcpy( s, src, len );
1075
1076        /* need to convert spaces to dashes for */
1077        /* add_style_name and setwidth_name     */
1078        if ( nn == 0 || nn == 3 )
1079        {
1080          int  mm;
1081
1082
1083          for ( mm = 0; mm < len; mm++ )
1084            if (s[mm] == ' ')
1085              s[mm] = '-';
1086        }
1087
1088        s += len;
1089      }
1090      *s = 0;
1091    }
1092
1093    return error;
1094  }
1095
1096
1097  FT_LOCAL_DEF( FT_Error )
1098  pcf_load_font( FT_Stream  stream,
1099                 PCF_Face   face )
1100  {
1101    FT_Error   error  = PCF_Err_Ok;
1102    FT_Memory  memory = FT_FACE(face)->memory;
1103    FT_Bool    hasBDFAccelerators;
1104
1105
1106    error = pcf_read_TOC( stream, face );
1107    if ( error )
1108      goto Exit;
1109
1110    error = pcf_get_properties( stream, face );
1111    if ( error )
1112      goto Exit;
1113
1114    /* Use the old accelerators if no BDF accelerators are in the file. */
1115    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1116                                             face->toc.count,
1117                                             PCF_BDF_ACCELERATORS );
1118    if ( !hasBDFAccelerators )
1119    {
1120      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1121      if ( error )
1122        goto Exit;
1123    }
1124
1125    /* metrics */
1126    error = pcf_get_metrics( stream, face );
1127    if ( error )
1128      goto Exit;
1129
1130    /* bitmaps */
1131    error = pcf_get_bitmaps( stream, face );
1132    if ( error )
1133      goto Exit;
1134
1135    /* encodings */
1136    error = pcf_get_encodings( stream, face );
1137    if ( error )
1138      goto Exit;
1139
1140    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1141    if ( hasBDFAccelerators )
1142    {
1143      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1144      if ( error )
1145        goto Exit;
1146    }
1147
1148    /* XXX: TO DO: inkmetrics and glyph_names are missing */
1149
1150    /* now construct the face object */
1151    {
1152      FT_Face       root = FT_FACE( face );
1153      PCF_Property  prop;
1154
1155
1156      root->num_faces  = 1;
1157      root->face_index = 0;
1158      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1159                         FT_FACE_FLAG_HORIZONTAL  |
1160                         FT_FACE_FLAG_FAST_GLYPHS;
1161
1162      if ( face->accel.constantWidth )
1163        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1164
1165      if ( ( error = pcf_interpret_style( face ) ) != 0 )
1166         goto Exit;
1167
1168      prop = pcf_find_property( face, "FAMILY_NAME" );
1169      if ( prop && prop->isString )
1170      {
1171        if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1172          goto Exit;
1173      }
1174      else
1175        root->family_name = NULL;
1176
1177      /*
1178       * Note: We shift all glyph indices by +1 since we must
1179       * respect the convention that glyph 0 always corresponds
1180       * to the `missing glyph'.
1181       *
1182       * This implies bumping the number of `available' glyphs by 1.
1183       */
1184      root->num_glyphs = face->nmetrics + 1;
1185
1186      root->num_fixed_sizes = 1;
1187      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1188        goto Exit;
1189
1190      {
1191        FT_Bitmap_Size*  bsize = root->available_sizes;
1192        FT_Short         resolution_x = 0, resolution_y = 0;
1193
1194
1195        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1196
1197#if 0
1198        bsize->height = face->accel.maxbounds.ascent << 6;
1199#endif
1200        bsize->height = (FT_Short)( face->accel.fontAscent +
1201                                    face->accel.fontDescent );
1202
1203        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1204        if ( prop )
1205          bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 );
1206        else
1207          bsize->width = (FT_Short)( bsize->height * 2/3 );
1208
1209        prop = pcf_find_property( face, "POINT_SIZE" );
1210        if ( prop )
1211          /* convert from 722.7 decipoints to 72 points per inch */
1212          bsize->size =
1213            (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L );
1214
1215        prop = pcf_find_property( face, "PIXEL_SIZE" );
1216        if ( prop )
1217          bsize->y_ppem = (FT_Short)prop->value.integer << 6;
1218
1219        prop = pcf_find_property( face, "RESOLUTION_X" );
1220        if ( prop )
1221          resolution_x = (FT_Short)prop->value.integer;
1222
1223        prop = pcf_find_property( face, "RESOLUTION_Y" );
1224        if ( prop )
1225          resolution_y = (FT_Short)prop->value.integer;
1226
1227        if ( bsize->y_ppem == 0 )
1228        {
1229          bsize->y_ppem = bsize->size;
1230          if ( resolution_y )
1231            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1232        }
1233        if ( resolution_x && resolution_y )
1234          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1235        else
1236          bsize->x_ppem = bsize->y_ppem;
1237      }
1238
1239      /* set up charset */
1240      {
1241        PCF_Property  charset_registry = 0, charset_encoding = 0;
1242
1243
1244        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1245        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1246
1247        if ( charset_registry && charset_registry->isString &&
1248             charset_encoding && charset_encoding->isString )
1249        {
1250          if ( FT_STRDUP( face->charset_encoding,
1251                          charset_encoding->value.atom ) ||
1252               FT_STRDUP( face->charset_registry,
1253                          charset_registry->value.atom ) )
1254            goto Exit;
1255        }
1256      }
1257    }
1258
1259  Exit:
1260    if ( error )
1261    {
1262      /* This is done to respect the behaviour of the original */
1263      /* PCF font driver.                                      */
1264      error = PCF_Err_Invalid_File_Format;
1265    }
1266
1267    return error;
1268  }
1269
1270
1271/* END */
Note: See TracBrowser for help on using the repository browser.