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

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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