Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / pcf / pcfread.c
blobb9123cf574f2736aeafda20199e62eff226a9bde
1 /* pcfread.c
3 FreeType font driver for pcf fonts
5 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by
6 Francesco Zappa Nardelli
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
28 #include <ft2build.h>
30 #include FT_INTERNAL_DEBUG_H
31 #include FT_INTERNAL_STREAM_H
32 #include FT_INTERNAL_OBJECTS_H
34 #include "pcf.h"
35 #include "pcfdrivr.h"
36 #include "pcfread.h"
38 #include "pcferror.h"
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
51 #if defined( FT_DEBUG_LEVEL_TRACE )
52 static const char* const tableNames[] =
54 "prop", "accl", "mtrcs", "bmps", "imtrcs",
55 "enc", "swidth", "names", "accel"
57 #endif
60 static
61 const FT_Frame_Field pcf_toc_header[] =
63 #undef FT_STRUCTURE
64 #define FT_STRUCTURE PCF_TocRec
66 FT_FRAME_START( 8 ),
67 FT_FRAME_ULONG_LE( version ),
68 FT_FRAME_ULONG_LE( count ),
69 FT_FRAME_END
73 static
74 const FT_Frame_Field pcf_table_header[] =
76 #undef FT_STRUCTURE
77 #define FT_STRUCTURE PCF_TableRec
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
88 static FT_Error
89 pcf_read_TOC( FT_Stream stream,
90 PCF_Face face )
92 FT_Error error;
93 PCF_Toc toc = &face->toc;
94 PCF_Table tables;
96 FT_Memory memory = FT_FACE(face)->memory;
97 FT_UInt n;
100 if ( FT_STREAM_SEEK ( 0 ) ||
101 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
102 return PCF_Err_Cannot_Open_Resource;
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;
109 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
110 return PCF_Err_Out_Of_Memory;
112 tables = face->toc.tables;
113 for ( n = 0; n < toc->count; n++ )
115 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
116 goto Exit;
117 tables++;
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;
125 for ( n = 0; n < toc->count - 1; n++ )
127 FT_UInt i, have_change;
130 have_change = 0;
132 for ( i = 0; i < toc->count - 1 - n; i++ )
134 PCF_TableRec tmp;
137 if ( tables[i].offset > tables[i + 1].offset )
139 tmp = tables[i];
140 tables[i] = tables[i + 1];
141 tables[i + 1] = tmp;
143 have_change = 1;
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;
151 if ( !have_change )
152 break;
155 #if defined( FT_DEBUG_LEVEL_TRACE )
158 FT_UInt i, j;
159 const char* name = "?";
162 FT_TRACE4(( "pcf_read_TOC:\n" ));
164 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
166 tables = face->toc.tables;
167 for ( i = 0; i < toc->count; i++ )
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];
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 ));
183 #endif
185 return PCF_Err_Ok;
187 Exit:
188 FT_FREE( face->toc.tables );
189 return error;
193 #define PCF_METRIC_SIZE 12
195 static
196 const FT_Frame_Field pcf_metric_header[] =
198 #undef FT_STRUCTURE
199 #define FT_STRUCTURE PCF_MetricRec
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
212 static
213 const FT_Frame_Field pcf_metric_msb_header[] =
215 #undef FT_STRUCTURE
216 #define FT_STRUCTURE PCF_MetricRec
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
229 #define PCF_COMPRESSED_METRIC_SIZE 5
231 static
232 const FT_Frame_Field pcf_compressed_metric_header[] =
234 #undef FT_STRUCTURE
235 #define FT_STRUCTURE PCF_Compressed_MetricRec
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
247 static FT_Error
248 pcf_get_metric( FT_Stream stream,
249 FT_ULong format,
250 PCF_Metric metric )
252 FT_Error error = PCF_Err_Ok;
255 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
257 const FT_Frame_Field* fields;
260 /* parsing normal metrics */
261 fields = PCF_BYTE_ORDER( format ) == MSBFirst
262 ? pcf_metric_msb_header
263 : pcf_metric_header;
265 /* the following sets `error' but doesn't return in case of failure */
266 (void)FT_STREAM_READ_FIELDS( fields, metric );
268 else
270 PCF_Compressed_MetricRec compr;
273 /* parsing compressed metrics */
274 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
275 goto Exit;
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;
285 Exit:
286 return error;
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 )
298 FT_Error error = PCF_Err_Invalid_File_Format;
299 FT_Int i;
302 for ( i = 0; i < ntables; i++ )
303 if ( tables[i].type == type )
305 if ( stream->pos > tables[i].offset )
307 error = PCF_Err_Invalid_Stream_Skip;
308 goto Fail;
311 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
313 error = PCF_Err_Invalid_Stream_Skip;
314 goto Fail;
317 *asize = tables[i].size;
318 *aformat = tables[i].format;
320 return PCF_Err_Ok;
323 Fail:
324 *asize = 0;
325 return error;
329 static FT_Bool
330 pcf_has_table_type( PCF_Table tables,
331 FT_Int ntables,
332 FT_ULong type )
334 FT_Int i;
337 for ( i = 0; i < ntables; i++ )
338 if ( tables[i].type == type )
339 return TRUE;
341 return FALSE;
345 #define PCF_PROPERTY_SIZE 9
347 static
348 const FT_Frame_Field pcf_property_header[] =
350 #undef FT_STRUCTURE
351 #define FT_STRUCTURE PCF_ParsePropertyRec
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
361 static
362 const FT_Frame_Field pcf_property_msb_header[] =
364 #undef FT_STRUCTURE
365 #define FT_STRUCTURE PCF_ParsePropertyRec
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
375 FT_LOCAL_DEF( PCF_Property )
376 pcf_find_property( PCF_Face face,
377 const FT_String* prop )
379 PCF_Property properties = face->properties;
380 FT_Bool found = 0;
381 int i;
384 for ( i = 0 ; i < face->nprops && !found; i++ )
386 if ( !ft_strcmp( properties[i].name, prop ) )
387 found = 1;
390 if ( found )
391 return properties + i - 1;
392 else
393 return NULL;
397 static FT_Error
398 pcf_get_properties( FT_Stream stream,
399 PCF_Face face )
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;
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;
420 if ( FT_READ_ULONG_LE( format ) )
421 goto Bail;
423 FT_TRACE4(( "pcf_get_properties:\n" ));
425 FT_TRACE4(( " format = %ld\n", format ));
427 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
428 goto Bail;
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;
437 FT_TRACE4(( " nprop = %d\n", nprops ));
439 /* rough estimate */
440 if ( nprops > size / PCF_PROPERTY_SIZE )
442 error = PCF_Err_Invalid_Table;
443 goto Bail;
446 face->nprops = nprops;
448 if ( FT_NEW_ARRAY( props, nprops ) )
449 goto Bail;
451 for ( i = 0; i < nprops; i++ )
453 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
455 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
456 goto Bail;
458 else
460 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
461 goto Bail;
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 )
472 i = 4 - ( nprops & 3 );
473 FT_Stream_Skip( stream, i );
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;
483 FT_TRACE4(( " string_size = %ld\n", string_size ));
485 /* rough estimate */
486 if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
488 error = PCF_Err_Invalid_Table;
489 goto Bail;
492 if ( FT_NEW_ARRAY( strings, string_size ) )
493 goto Bail;
495 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
496 if ( error )
497 goto Bail;
499 if ( FT_NEW_ARRAY( properties, nprops ) )
500 goto Bail;
502 face->properties = properties;
504 for ( i = 0; i < nprops; i++ )
506 FT_Long name_offset = props[i].name;
509 if ( ( name_offset < 0 ) ||
510 ( (FT_ULong)name_offset > string_size ) )
512 error = PCF_Err_Invalid_Offset;
513 goto Bail;
516 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
517 goto Bail;
519 FT_TRACE4(( " %s:", properties[i].name ));
521 properties[i].isString = props[i].isString;
523 if ( props[i].isString )
525 FT_Long value_offset = props[i].value;
528 if ( ( value_offset < 0 ) ||
529 ( (FT_ULong)value_offset > string_size ) )
531 error = PCF_Err_Invalid_Offset;
532 goto Bail;
535 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
536 goto Bail;
538 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
540 else
542 properties[i].value.integer = props[i].value;
544 FT_TRACE4(( " %d\n", properties[i].value.integer ));
548 error = PCF_Err_Ok;
550 Bail:
551 FT_FREE( props );
552 FT_FREE( strings );
554 return error;
558 static FT_Error
559 pcf_get_metrics( FT_Stream stream,
560 PCF_Face face )
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;
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;
578 if ( FT_READ_ULONG_LE( format ) )
579 goto Bail;
581 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
582 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
583 return PCF_Err_Invalid_File_Format;
585 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
587 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
588 (void)FT_READ_ULONG( nmetrics );
589 else
590 (void)FT_READ_ULONG_LE( nmetrics );
592 else
594 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
595 (void)FT_READ_USHORT( nmetrics );
596 else
597 (void)FT_READ_USHORT_LE( nmetrics );
599 if ( error )
600 return PCF_Err_Invalid_File_Format;
602 face->nmetrics = nmetrics;
604 FT_TRACE4(( "pcf_get_metrics:\n" ));
606 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
608 /* rough estimate */
609 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
611 if ( nmetrics > size / PCF_METRIC_SIZE )
612 return PCF_Err_Invalid_Table;
614 else
616 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
617 return PCF_Err_Invalid_Table;
620 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
621 return PCF_Err_Out_Of_Memory;
623 metrics = face->metrics;
624 for ( i = 0; i < nmetrics; i++ )
626 pcf_get_metric( stream, format, metrics + i );
628 metrics[i].bits = 0;
630 FT_TRACE5(( " idx %d: width=%d, "
631 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
633 ( metrics + i )->characterWidth,
634 ( metrics + i )->leftSideBearing,
635 ( metrics + i )->rightSideBearing,
636 ( metrics + i )->ascent,
637 ( metrics + i )->descent,
638 ( metrics + i )->attributes ));
640 if ( error )
641 break;
644 if ( error )
645 FT_FREE( face->metrics );
647 Bail:
648 return error;
652 static FT_Error
653 pcf_get_bitmaps( FT_Stream stream,
654 PCF_Face face )
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;
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;
673 error = FT_Stream_EnterFrame( stream, 8 );
674 if ( error )
675 return error;
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();
683 FT_Stream_ExitFrame( stream );
685 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
686 return PCF_Err_Invalid_File_Format;
688 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
690 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
692 if ( nbitmaps != face->nmetrics )
693 return PCF_Err_Invalid_File_Format;
695 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
696 return error;
698 for ( i = 0; i < nbitmaps; i++ )
700 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
701 (void)FT_READ_LONG( offsets[i] );
702 else
703 (void)FT_READ_LONG_LE( offsets[i] );
705 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
706 i, offsets[i], offsets[i] ));
708 if ( error )
709 goto Bail;
711 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
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;
720 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
722 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
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 ));
730 FT_UNUSED( sizebitmaps ); /* only used for debugging */
732 for ( i = 0; i < nbitmaps; i++ )
734 /* rough estimate */
735 if ( ( offsets[i] < 0 ) ||
736 ( (FT_ULong)offsets[i] > size ) )
738 FT_ERROR(( "pcf_get_bitmaps:"));
739 FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i ));
741 else
742 face->metrics[i].bits = stream->pos + offsets[i];
745 face->bitmapsFormat = format;
747 Bail:
748 FT_FREE( offsets );
749 return error;
753 static FT_Error
754 pcf_get_encodings( FT_Stream stream,
755 PCF_Face face )
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;
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;
776 error = FT_Stream_EnterFrame( stream, 14 );
777 if ( error )
778 return error;
780 format = FT_GET_ULONG_LE();
782 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
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();
790 else
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();
799 FT_Stream_ExitFrame( stream );
801 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
802 return PCF_Err_Invalid_File_Format;
804 FT_TRACE4(( "pdf_get_encodings:\n" ));
806 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
807 firstCol, lastCol, firstRow, lastRow ));
809 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
811 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
812 return PCF_Err_Out_Of_Memory;
814 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
815 if ( error )
816 goto Bail;
818 for ( i = 0, j = 0 ; i < nencoding; i++ )
820 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
821 encodingOffset = FT_GET_SHORT();
822 else
823 encodingOffset = FT_GET_SHORT_LE();
825 if ( encodingOffset != -1 )
827 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
828 firstRow ) * 256 ) +
829 ( ( i % ( lastCol - firstCol + 1 ) ) +
830 firstCol );
832 tmpEncoding[j].glyph = (FT_Short)encodingOffset;
834 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
835 tmpEncoding[j].enc, tmpEncoding[j].enc,
836 tmpEncoding[j].glyph ));
838 j++;
841 FT_Stream_ExitFrame( stream );
843 if ( FT_NEW_ARRAY( encoding, j ) )
844 goto Bail;
846 for ( i = 0; i < j; i++ )
848 encoding[i].enc = tmpEncoding[i].enc;
849 encoding[i].glyph = tmpEncoding[i].glyph;
852 face->nencodings = j;
853 face->encodings = encoding;
854 FT_FREE( tmpEncoding );
856 return error;
858 Bail:
859 FT_FREE( encoding );
860 FT_FREE( tmpEncoding );
861 return error;
865 static
866 const FT_Frame_Field pcf_accel_header[] =
868 #undef FT_STRUCTURE
869 #define FT_STRUCTURE PCF_AccelRec
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
887 static
888 const FT_Frame_Field pcf_accel_msb_header[] =
890 #undef FT_STRUCTURE
891 #define FT_STRUCTURE PCF_AccelRec
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
909 static FT_Error
910 pcf_get_accel( FT_Stream stream,
911 PCF_Face face,
912 FT_ULong type )
914 FT_ULong format, size;
915 FT_Error error = PCF_Err_Ok;
916 PCF_Accel accel = &face->accel;
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;
928 if ( FT_READ_ULONG_LE( format ) )
929 goto Bail;
931 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
932 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
933 goto Bail;
935 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
937 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
938 goto Bail;
940 else
942 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
943 goto Bail;
946 error = pcf_get_metric( stream,
947 format & ( ~PCF_FORMAT_MASK ),
948 &(accel->minbounds) );
949 if ( error )
950 goto Bail;
952 error = pcf_get_metric( stream,
953 format & ( ~PCF_FORMAT_MASK ),
954 &(accel->maxbounds) );
955 if ( error )
956 goto Bail;
958 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
960 error = pcf_get_metric( stream,
961 format & ( ~PCF_FORMAT_MASK ),
962 &(accel->ink_minbounds) );
963 if ( error )
964 goto Bail;
966 error = pcf_get_metric( stream,
967 format & ( ~PCF_FORMAT_MASK ),
968 &(accel->ink_maxbounds) );
969 if ( error )
970 goto Bail;
972 else
974 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
975 accel->ink_maxbounds = accel->maxbounds;
978 Bail:
979 return error;
983 static FT_Error
984 pcf_interpret_style( PCF_Face pcf )
986 FT_Error error = PCF_Err_Ok;
987 FT_Face face = FT_FACE( pcf );
988 FT_Memory memory = face->memory;
990 PCF_Property prop;
992 int nn, len;
993 char* strings[4] = { NULL, NULL, NULL, NULL };
994 int lengths[4];
997 face->style_flags = 0;
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' ) )
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";
1010 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1011 if ( prop && prop->isString &&
1012 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1014 face->style_flags |= FT_STYLE_FLAG_BOLD;
1015 strings[1] = (char *)"Bold";
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);
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);
1030 for ( len = 0, nn = 0; nn < 4; nn++ )
1032 lengths[nn] = 0;
1033 if ( strings[nn] )
1035 lengths[nn] = ft_strlen( strings[nn] );
1036 len += lengths[nn] + 1;
1040 if ( len == 0 )
1042 strings[0] = (char *)"Regular";
1043 lengths[0] = ft_strlen( strings[0] );
1044 len = lengths[0] + 1;
1048 char* s;
1051 if ( FT_ALLOC( face->style_name, len ) )
1052 return error;
1054 s = face->style_name;
1056 for ( nn = 0; nn < 4; nn++ )
1058 char* src = strings[nn];
1061 len = lengths[nn];
1063 if ( src == NULL )
1064 continue;
1066 /* separate elements with a space */
1067 if ( s != face->style_name )
1068 *s++ = ' ';
1070 ft_memcpy( s, src, len );
1072 /* need to convert spaces to dashes for */
1073 /* add_style_name and setwidth_name */
1074 if ( nn == 0 || nn == 3 )
1076 int mm;
1079 for ( mm = 0; mm < len; mm++ )
1080 if (s[mm] == ' ')
1081 s[mm] = '-';
1084 s += len;
1086 *s = 0;
1089 return error;
1093 FT_LOCAL_DEF( FT_Error )
1094 pcf_load_font( FT_Stream stream,
1095 PCF_Face face )
1097 FT_Error error = PCF_Err_Ok;
1098 FT_Memory memory = FT_FACE(face)->memory;
1099 FT_Bool hasBDFAccelerators;
1102 error = pcf_read_TOC( stream, face );
1103 if ( error )
1104 goto Exit;
1106 error = pcf_get_properties( stream, face );
1107 if ( error )
1108 goto Exit;
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 )
1116 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1117 if ( error )
1118 goto Exit;
1121 /* metrics */
1122 error = pcf_get_metrics( stream, face );
1123 if ( error )
1124 goto Exit;
1126 /* bitmaps */
1127 error = pcf_get_bitmaps( stream, face );
1128 if ( error )
1129 goto Exit;
1131 /* encodings */
1132 error = pcf_get_encodings( stream, face );
1133 if ( error )
1134 goto Exit;
1136 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1137 if ( hasBDFAccelerators )
1139 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1140 if ( error )
1141 goto Exit;
1144 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1146 /* now construct the face object */
1148 FT_Face root = FT_FACE( face );
1149 PCF_Property prop;
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;
1158 if ( face->accel.constantWidth )
1159 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1161 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1162 goto Exit;
1164 prop = pcf_find_property( face, "FAMILY_NAME" );
1165 if ( prop && prop->isString )
1167 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1168 goto Exit;
1170 else
1171 root->family_name = NULL;
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'.
1178 * This implies bumping the number of `available' glyphs by 1.
1180 root->num_glyphs = face->nmetrics + 1;
1182 root->num_fixed_sizes = 1;
1183 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1184 goto Exit;
1187 FT_Bitmap_Size* bsize = root->available_sizes;
1188 FT_Short resolution_x = 0, resolution_y = 0;
1191 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
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 );
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 );
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 );
1211 prop = pcf_find_property( face, "PIXEL_SIZE" );
1212 if ( prop )
1213 bsize->y_ppem = (FT_Short)prop->value.integer << 6;
1215 prop = pcf_find_property( face, "RESOLUTION_X" );
1216 if ( prop )
1217 resolution_x = (FT_Short)prop->value.integer;
1219 prop = pcf_find_property( face, "RESOLUTION_Y" );
1220 if ( prop )
1221 resolution_y = (FT_Short)prop->value.integer;
1223 if ( bsize->y_ppem == 0 )
1225 bsize->y_ppem = bsize->size;
1226 if ( resolution_y )
1227 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
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;
1235 /* set up charset */
1237 PCF_Property charset_registry = 0, charset_encoding = 0;
1240 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1241 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1243 if ( charset_registry && charset_registry->isString &&
1244 charset_encoding && charset_encoding->isString )
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;
1255 Exit:
1256 if ( error )
1258 /* This is done to respect the behaviour of the original */
1259 /* PCF font driver. */
1260 error = PCF_Err_Invalid_File_Format;
1263 return error;
1267 /* END */