3 FreeType font driver for pcf fonts
5 Copyright 2000-2010, 2012-2014 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
30 #include FT_INTERNAL_DEBUG_H
31 #include FT_INTERNAL_STREAM_H
32 #include FT_INTERNAL_OBJECTS_H
40 /*************************************************************************/
42 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
43 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
44 /* messages during execution. */
47 #define FT_COMPONENT trace_pcfread
50 #ifdef FT_DEBUG_LEVEL_TRACE
51 static const char* const tableNames[] =
53 "prop", "accl", "mtrcs", "bmps", "imtrcs",
54 "enc", "swidth", "names", "accel"
60 const FT_Frame_Field pcf_toc_header[] =
63 #define FT_STRUCTURE PCF_TocRec
66 FT_FRAME_ULONG_LE( version ),
67 FT_FRAME_ULONG_LE( count ),
73 const FT_Frame_Field pcf_table_header[] =
76 #define FT_STRUCTURE PCF_TableRec
79 FT_FRAME_ULONG_LE( type ),
80 FT_FRAME_ULONG_LE( format ),
81 FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */
82 FT_FRAME_ULONG_LE( offset ),
88 pcf_read_TOC( FT_Stream stream,
92 PCF_Toc toc = &face->toc;
95 FT_Memory memory = FT_FACE( face )->memory;
101 if ( FT_STREAM_SEEK( 0 ) ||
102 FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) )
103 return FT_THROW( Cannot_Open_Resource );
105 if ( toc->version != PCF_FILE_VERSION ||
106 toc->count > FT_ARRAY_MAX( face->toc.tables ) ||
108 return FT_THROW( Invalid_File_Format );
110 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
111 return FT_THROW( Out_Of_Memory );
113 tables = face->toc.tables;
114 for ( n = 0; n < toc->count; n++ )
116 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
121 /* Sort tables and check for overlaps. Because they are almost */
122 /* always ordered already, an in-place bubble sort with simultaneous */
123 /* boundary checking seems appropriate. */
124 tables = face->toc.tables;
126 for ( n = 0; n < toc->count - 1; n++ )
128 FT_UInt i, have_change;
133 for ( i = 0; i < toc->count - 1 - n; i++ )
138 if ( tables[i].offset > tables[i + 1].offset )
141 tables[i] = tables[i + 1];
147 if ( ( tables[i].size > tables[i + 1].offset ) ||
148 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
150 error = FT_THROW( Invalid_Offset );
160 * We now check whether the `size' and `offset' values are reasonable:
161 * `offset' + `size' must not exceed the stream size.
163 * Note, however, that X11's `pcfWriteFont' routine (used by the
164 * `bdftopcf' program to create PDF font files) has two special
167 * - It always assigns the accelerator table a size of 100 bytes in the
168 * TOC, regardless of its real size, which can vary between 34 and 72
171 * - Due to the way the routine is designed, it ships out the last font
172 * table with its real size, ignoring the TOC's size value. Since
173 * the TOC size values are always rounded up to a multiple of 4, the
174 * difference can be up to three bytes for all tables except the
175 * accelerator table, for which the difference can be as large as 66
180 tables = face->toc.tables;
183 for ( n = 0; n < toc->count - 1; n++ )
185 /* we need two checks to avoid overflow */
186 if ( ( tables->size > size ) ||
187 ( tables->offset > size - tables->size ) )
189 error = FT_THROW( Invalid_Table );
195 /* only check `tables->offset' for last table element ... */
196 if ( ( tables->offset > size ) )
198 error = FT_THROW( Invalid_Table );
201 /* ... and adjust `tables->size' to the real value if necessary */
202 if ( tables->size > size - tables->offset )
203 tables->size = size - tables->offset;
205 #ifdef FT_DEBUG_LEVEL_TRACE
209 const char* name = "?";
212 FT_TRACE4(( "pcf_read_TOC:\n" ));
214 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
216 tables = face->toc.tables;
217 for ( i = 0; i < toc->count; i++ )
219 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
221 if ( tables[i].type == (FT_UInt)( 1 << j ) )
222 name = tableNames[j];
224 FT_TRACE4(( " %d: type=%s, format=0x%X, "
225 "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
228 tables[i].size, tables[i].size,
229 tables[i].offset, tables[i].offset ));
238 FT_FREE( face->toc.tables );
243 #define PCF_METRIC_SIZE 12
246 const FT_Frame_Field pcf_metric_header[] =
249 #define FT_STRUCTURE PCF_MetricRec
251 FT_FRAME_START( PCF_METRIC_SIZE ),
252 FT_FRAME_SHORT_LE( leftSideBearing ),
253 FT_FRAME_SHORT_LE( rightSideBearing ),
254 FT_FRAME_SHORT_LE( characterWidth ),
255 FT_FRAME_SHORT_LE( ascent ),
256 FT_FRAME_SHORT_LE( descent ),
257 FT_FRAME_SHORT_LE( attributes ),
263 const FT_Frame_Field pcf_metric_msb_header[] =
266 #define FT_STRUCTURE PCF_MetricRec
268 FT_FRAME_START( PCF_METRIC_SIZE ),
269 FT_FRAME_SHORT( leftSideBearing ),
270 FT_FRAME_SHORT( rightSideBearing ),
271 FT_FRAME_SHORT( characterWidth ),
272 FT_FRAME_SHORT( ascent ),
273 FT_FRAME_SHORT( descent ),
274 FT_FRAME_SHORT( attributes ),
279 #define PCF_COMPRESSED_METRIC_SIZE 5
282 const FT_Frame_Field pcf_compressed_metric_header[] =
285 #define FT_STRUCTURE PCF_Compressed_MetricRec
287 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
288 FT_FRAME_BYTE( leftSideBearing ),
289 FT_FRAME_BYTE( rightSideBearing ),
290 FT_FRAME_BYTE( characterWidth ),
291 FT_FRAME_BYTE( ascent ),
292 FT_FRAME_BYTE( descent ),
298 pcf_get_metric( FT_Stream stream,
302 FT_Error error = FT_Err_Ok;
305 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
307 const FT_Frame_Field* fields;
310 /* parsing normal metrics */
311 fields = PCF_BYTE_ORDER( format ) == MSBFirst
312 ? pcf_metric_msb_header
315 /* the following sets `error' but doesn't return in case of failure */
316 (void)FT_STREAM_READ_FIELDS( fields, metric );
320 PCF_Compressed_MetricRec compr;
323 /* parsing compressed metrics */
324 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
327 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
328 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
329 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
330 metric->ascent = (FT_Short)( compr.ascent - 0x80 );
331 metric->descent = (FT_Short)( compr.descent - 0x80 );
332 metric->attributes = 0;
341 pcf_seek_to_table_type( FT_Stream stream,
343 FT_ULong ntables, /* same as PCF_Toc->count */
348 FT_Error error = FT_ERR( Invalid_File_Format );
352 for ( i = 0; i < ntables; i++ )
353 if ( tables[i].type == type )
355 if ( stream->pos > tables[i].offset )
357 error = FT_THROW( Invalid_Stream_Skip );
361 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
363 error = FT_THROW( Invalid_Stream_Skip );
367 *asize = tables[i].size;
368 *aformat = tables[i].format;
380 pcf_has_table_type( PCF_Table tables,
381 FT_ULong ntables, /* same as PCF_Toc->count */
387 for ( i = 0; i < ntables; i++ )
388 if ( tables[i].type == type )
395 #define PCF_PROPERTY_SIZE 9
398 const FT_Frame_Field pcf_property_header[] =
401 #define FT_STRUCTURE PCF_ParsePropertyRec
403 FT_FRAME_START( PCF_PROPERTY_SIZE ),
404 FT_FRAME_LONG_LE( name ),
405 FT_FRAME_BYTE ( isString ),
406 FT_FRAME_LONG_LE( value ),
412 const FT_Frame_Field pcf_property_msb_header[] =
415 #define FT_STRUCTURE PCF_ParsePropertyRec
417 FT_FRAME_START( PCF_PROPERTY_SIZE ),
418 FT_FRAME_LONG( name ),
419 FT_FRAME_BYTE( isString ),
420 FT_FRAME_LONG( value ),
425 FT_LOCAL_DEF( PCF_Property )
426 pcf_find_property( PCF_Face face,
427 const FT_String* prop )
429 PCF_Property properties = face->properties;
434 for ( i = 0 ; i < face->nprops && !found; i++ )
436 if ( !ft_strcmp( properties[i].name, prop ) )
441 return properties + i - 1;
448 pcf_get_properties( FT_Stream stream,
451 PCF_ParseProperty props = 0;
452 PCF_Property properties = NULL;
454 FT_ULong format, size;
456 FT_Memory memory = FT_FACE( face )->memory;
457 FT_ULong string_size;
458 FT_String* strings = 0;
461 error = pcf_seek_to_table_type( stream,
470 if ( FT_READ_ULONG_LE( format ) )
473 FT_TRACE4(( "pcf_get_properties:\n" ));
475 FT_TRACE4(( " format = %ld\n", format ));
477 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
480 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
481 (void)FT_READ_ULONG( nprops );
483 (void)FT_READ_ULONG_LE( nprops );
487 FT_TRACE4(( " nprop = %d (truncate %d props)\n",
488 (int)nprops, nprops - (int)nprops ));
490 nprops = (int)nprops;
493 if ( nprops > size / PCF_PROPERTY_SIZE )
495 error = FT_THROW( Invalid_Table );
499 face->nprops = (int)nprops;
501 if ( FT_NEW_ARRAY( props, nprops ) )
504 for ( i = 0; i < nprops; i++ )
506 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
508 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
513 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
518 /* pad the property array */
520 /* clever here - nprops is the same as the number of odd-units read, */
521 /* as only isStringProp are odd length (Keith Packard) */
525 i = 4 - ( nprops & 3 );
526 if ( FT_STREAM_SKIP( i ) )
528 error = FT_THROW( Invalid_Stream_Skip );
533 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
534 (void)FT_READ_ULONG( string_size );
536 (void)FT_READ_ULONG_LE( string_size );
540 FT_TRACE4(( " string_size = %ld\n", string_size ));
543 if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
545 error = FT_THROW( Invalid_Table );
549 /* allocate one more byte so that we have a final null byte */
550 if ( FT_NEW_ARRAY( strings, string_size + 1 ) )
553 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
557 if ( FT_NEW_ARRAY( properties, nprops ) )
560 face->properties = properties;
562 for ( i = 0; i < nprops; i++ )
564 FT_Long name_offset = props[i].name;
567 if ( ( name_offset < 0 ) ||
568 ( (FT_ULong)name_offset > string_size ) )
570 error = FT_THROW( Invalid_Offset );
574 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
577 FT_TRACE4(( " %s:", properties[i].name ));
579 properties[i].isString = props[i].isString;
581 if ( props[i].isString )
583 FT_Long value_offset = props[i].value;
586 if ( ( value_offset < 0 ) ||
587 ( (FT_ULong)value_offset > string_size ) )
589 error = FT_THROW( Invalid_Offset );
593 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
596 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
600 properties[i].value.l = props[i].value;
602 FT_TRACE4(( " %d\n", properties[i].value.l ));
617 pcf_get_metrics( FT_Stream stream,
621 FT_Memory memory = FT_FACE( face )->memory;
622 FT_ULong format, size;
623 PCF_Metric metrics = 0;
624 FT_ULong nmetrics, i;
627 error = pcf_seek_to_table_type( stream,
636 if ( FT_READ_ULONG_LE( format ) )
639 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
640 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
641 return FT_THROW( Invalid_File_Format );
643 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
645 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
646 (void)FT_READ_ULONG( nmetrics );
648 (void)FT_READ_ULONG_LE( nmetrics );
652 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
653 (void)FT_READ_USHORT( nmetrics );
655 (void)FT_READ_USHORT_LE( nmetrics );
658 return FT_THROW( Invalid_File_Format );
660 face->nmetrics = nmetrics;
663 return FT_THROW( Invalid_Table );
665 FT_TRACE4(( "pcf_get_metrics:\n" ));
667 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
670 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
672 if ( nmetrics > size / PCF_METRIC_SIZE )
673 return FT_THROW( Invalid_Table );
677 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
678 return FT_THROW( Invalid_Table );
681 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
682 return FT_THROW( Out_Of_Memory );
684 metrics = face->metrics;
685 for ( i = 0; i < nmetrics; i++, metrics++ )
687 error = pcf_get_metric( stream, format, metrics );
691 FT_TRACE5(( " idx %d: width=%d, "
692 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
694 metrics->characterWidth,
695 metrics->leftSideBearing,
696 metrics->rightSideBearing,
699 metrics->attributes ));
704 /* sanity checks -- those values are used in `PCF_Glyph_Load' to */
705 /* compute a glyph's bitmap dimensions, thus setting them to zero in */
706 /* case of an error disables this particular glyph only */
707 if ( metrics->rightSideBearing < metrics->leftSideBearing ||
708 metrics->ascent + metrics->descent < 0 )
710 metrics->characterWidth = 0;
711 metrics->leftSideBearing = 0;
712 metrics->rightSideBearing = 0;
714 metrics->descent = 0;
716 FT_TRACE0(( "pcf_get_metrics:"
717 " invalid metrics for glyph %d\n", i ));
722 FT_FREE( face->metrics );
730 pcf_get_bitmaps( FT_Stream stream,
734 FT_Memory memory = FT_FACE( face )->memory;
735 FT_Long* offsets = NULL;
736 FT_Long bitmapSizes[GLYPHPADOPTIONS];
737 FT_ULong format, size;
738 FT_ULong nbitmaps, i, sizebitmaps = 0;
741 error = pcf_seek_to_table_type( stream,
750 error = FT_Stream_EnterFrame( stream, 8 );
754 format = FT_GET_ULONG_LE();
755 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
756 nbitmaps = FT_GET_ULONG();
758 nbitmaps = FT_GET_ULONG_LE();
760 FT_Stream_ExitFrame( stream );
762 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
763 return FT_THROW( Invalid_File_Format );
765 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
767 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
769 /* XXX: PCF_Face->nmetrics is signed FT_Long, see pcf.h */
770 if ( face->nmetrics < 0 || nbitmaps != (FT_ULong)face->nmetrics )
771 return FT_THROW( Invalid_File_Format );
773 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
776 for ( i = 0; i < nbitmaps; i++ )
778 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
779 (void)FT_READ_LONG( offsets[i] );
781 (void)FT_READ_LONG_LE( offsets[i] );
783 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
784 i, offsets[i], offsets[i] ));
789 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
791 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
792 (void)FT_READ_LONG( bitmapSizes[i] );
794 (void)FT_READ_LONG_LE( bitmapSizes[i] );
798 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
800 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
803 FT_TRACE4(( " %d bitmaps, padding index %ld\n",
805 PCF_GLYPH_PAD_INDEX( format ) ));
806 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps ));
808 FT_UNUSED( sizebitmaps ); /* only used for debugging */
810 for ( i = 0; i < nbitmaps; i++ )
813 if ( ( offsets[i] < 0 ) ||
814 ( (FT_ULong)offsets[i] > size ) )
816 FT_TRACE0(( "pcf_get_bitmaps:"
817 " invalid offset to bitmap data of glyph %d\n", i ));
820 face->metrics[i].bits = stream->pos + offsets[i];
823 face->bitmapsFormat = format;
832 pcf_get_encodings( FT_Stream stream,
836 FT_Memory memory = FT_FACE( face )->memory;
837 FT_ULong format, size;
838 int firstCol, lastCol;
839 int firstRow, lastRow;
840 int nencoding, encodingOffset;
842 PCF_Encoding encoding = NULL;
845 error = pcf_seek_to_table_type( stream,
854 error = FT_Stream_EnterFrame( stream, 14 );
858 format = FT_GET_ULONG_LE();
860 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
862 firstCol = FT_GET_SHORT();
863 lastCol = FT_GET_SHORT();
864 firstRow = FT_GET_SHORT();
865 lastRow = FT_GET_SHORT();
866 face->defaultChar = FT_GET_SHORT();
870 firstCol = FT_GET_SHORT_LE();
871 lastCol = FT_GET_SHORT_LE();
872 firstRow = FT_GET_SHORT_LE();
873 lastRow = FT_GET_SHORT_LE();
874 face->defaultChar = FT_GET_SHORT_LE();
877 FT_Stream_ExitFrame( stream );
879 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
880 return FT_THROW( Invalid_File_Format );
884 firstCol > lastCol ||
887 firstRow > lastRow ||
889 return FT_THROW( Invalid_Table );
891 FT_TRACE4(( "pdf_get_encodings:\n" ));
893 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
894 firstCol, lastCol, firstRow, lastRow ));
896 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
898 if ( FT_NEW_ARRAY( encoding, nencoding ) )
899 return FT_THROW( Out_Of_Memory );
901 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
906 for ( i = firstRow; i <= lastRow; i++ )
908 for ( j = firstCol; j <= lastCol; j++ )
910 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
911 encodingOffset = FT_GET_SHORT();
913 encodingOffset = FT_GET_SHORT_LE();
915 if ( encodingOffset != -1 )
917 encoding[k].enc = i * 256 + j;
918 encoding[k].glyph = (FT_Short)encodingOffset;
920 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
921 encoding[k].enc, encoding[k].enc, encoding[k].glyph ));
927 FT_Stream_ExitFrame( stream );
929 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) )
932 face->nencodings = k;
933 face->encodings = encoding;
944 const FT_Frame_Field pcf_accel_header[] =
947 #define FT_STRUCTURE PCF_AccelRec
949 FT_FRAME_START( 20 ),
950 FT_FRAME_BYTE ( noOverlap ),
951 FT_FRAME_BYTE ( constantMetrics ),
952 FT_FRAME_BYTE ( terminalFont ),
953 FT_FRAME_BYTE ( constantWidth ),
954 FT_FRAME_BYTE ( inkInside ),
955 FT_FRAME_BYTE ( inkMetrics ),
956 FT_FRAME_BYTE ( drawDirection ),
957 FT_FRAME_SKIP_BYTES( 1 ),
958 FT_FRAME_LONG_LE ( fontAscent ),
959 FT_FRAME_LONG_LE ( fontDescent ),
960 FT_FRAME_LONG_LE ( maxOverlap ),
966 const FT_Frame_Field pcf_accel_msb_header[] =
969 #define FT_STRUCTURE PCF_AccelRec
971 FT_FRAME_START( 20 ),
972 FT_FRAME_BYTE ( noOverlap ),
973 FT_FRAME_BYTE ( constantMetrics ),
974 FT_FRAME_BYTE ( terminalFont ),
975 FT_FRAME_BYTE ( constantWidth ),
976 FT_FRAME_BYTE ( inkInside ),
977 FT_FRAME_BYTE ( inkMetrics ),
978 FT_FRAME_BYTE ( drawDirection ),
979 FT_FRAME_SKIP_BYTES( 1 ),
980 FT_FRAME_LONG ( fontAscent ),
981 FT_FRAME_LONG ( fontDescent ),
982 FT_FRAME_LONG ( maxOverlap ),
988 pcf_get_accel( FT_Stream stream,
992 FT_ULong format, size;
994 PCF_Accel accel = &face->accel;
997 error = pcf_seek_to_table_type( stream,
1006 if ( FT_READ_ULONG_LE( format ) )
1009 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
1010 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1013 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1015 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
1020 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
1024 error = pcf_get_metric( stream,
1025 format & ( ~PCF_FORMAT_MASK ),
1026 &(accel->minbounds) );
1030 error = pcf_get_metric( stream,
1031 format & ( ~PCF_FORMAT_MASK ),
1032 &(accel->maxbounds) );
1036 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1038 error = pcf_get_metric( stream,
1039 format & ( ~PCF_FORMAT_MASK ),
1040 &(accel->ink_minbounds) );
1044 error = pcf_get_metric( stream,
1045 format & ( ~PCF_FORMAT_MASK ),
1046 &(accel->ink_maxbounds) );
1052 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
1053 accel->ink_maxbounds = accel->maxbounds;
1062 pcf_interpret_style( PCF_Face pcf )
1064 FT_Error error = FT_Err_Ok;
1065 FT_Face face = FT_FACE( pcf );
1066 FT_Memory memory = face->memory;
1071 char* strings[4] = { NULL, NULL, NULL, NULL };
1075 face->style_flags = 0;
1077 prop = pcf_find_property( pcf, "SLANT" );
1078 if ( prop && prop->isString &&
1079 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1080 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1082 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1083 strings[2] = ( *(prop->value.atom) == 'O' ||
1084 *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1088 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1089 if ( prop && prop->isString &&
1090 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1092 face->style_flags |= FT_STYLE_FLAG_BOLD;
1093 strings[1] = (char*)"Bold";
1096 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1097 if ( prop && prop->isString &&
1098 *(prop->value.atom) &&
1099 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1100 strings[3] = (char*)( prop->value.atom );
1102 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1103 if ( prop && prop->isString &&
1104 *(prop->value.atom) &&
1105 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1106 strings[0] = (char*)( prop->value.atom );
1108 for ( len = 0, nn = 0; nn < 4; nn++ )
1113 lengths[nn] = ft_strlen( strings[nn] );
1114 len += lengths[nn] + 1;
1120 strings[0] = (char*)"Regular";
1121 lengths[0] = ft_strlen( strings[0] );
1122 len = lengths[0] + 1;
1129 if ( FT_ALLOC( face->style_name, len ) )
1132 s = face->style_name;
1134 for ( nn = 0; nn < 4; nn++ )
1136 char* src = strings[nn];
1144 /* separate elements with a space */
1145 if ( s != face->style_name )
1148 ft_memcpy( s, src, len );
1150 /* need to convert spaces to dashes for */
1151 /* add_style_name and setwidth_name */
1152 if ( nn == 0 || nn == 3 )
1157 for ( mm = 0; mm < len; mm++ )
1171 FT_LOCAL_DEF( FT_Error )
1172 pcf_load_font( FT_Stream stream,
1176 FT_Memory memory = FT_FACE( face )->memory;
1177 FT_Bool hasBDFAccelerators;
1180 error = pcf_read_TOC( stream, face );
1184 error = pcf_get_properties( stream, face );
1188 /* Use the old accelerators if no BDF accelerators are in the file. */
1189 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1191 PCF_BDF_ACCELERATORS );
1192 if ( !hasBDFAccelerators )
1194 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1200 error = pcf_get_metrics( stream, face );
1205 error = pcf_get_bitmaps( stream, face );
1210 error = pcf_get_encodings( stream, face );
1214 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1215 if ( hasBDFAccelerators )
1217 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1222 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1224 /* now construct the face object */
1226 FT_Face root = FT_FACE( face );
1230 root->num_faces = 1;
1231 root->face_index = 0;
1233 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
1234 FT_FACE_FLAG_HORIZONTAL |
1235 FT_FACE_FLAG_FAST_GLYPHS;
1237 if ( face->accel.constantWidth )
1238 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1240 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1243 prop = pcf_find_property( face, "FAMILY_NAME" );
1244 if ( prop && prop->isString )
1246 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1250 root->family_name = NULL;
1253 * Note: We shift all glyph indices by +1 since we must
1254 * respect the convention that glyph 0 always corresponds
1255 * to the `missing glyph'.
1257 * This implies bumping the number of `available' glyphs by 1.
1259 root->num_glyphs = face->nmetrics + 1;
1261 root->num_fixed_sizes = 1;
1262 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1266 FT_Bitmap_Size* bsize = root->available_sizes;
1267 FT_Short resolution_x = 0, resolution_y = 0;
1270 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1273 bsize->height = face->accel.maxbounds.ascent << 6;
1275 bsize->height = (FT_Short)( face->accel.fontAscent +
1276 face->accel.fontDescent );
1278 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1280 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1282 bsize->width = (FT_Short)( bsize->height * 2/3 );
1284 prop = pcf_find_property( face, "POINT_SIZE" );
1286 /* convert from 722.7 decipoints to 72 points per inch */
1288 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1290 prop = pcf_find_property( face, "PIXEL_SIZE" );
1292 bsize->y_ppem = (FT_Short)prop->value.l << 6;
1294 prop = pcf_find_property( face, "RESOLUTION_X" );
1296 resolution_x = (FT_Short)prop->value.l;
1298 prop = pcf_find_property( face, "RESOLUTION_Y" );
1300 resolution_y = (FT_Short)prop->value.l;
1302 if ( bsize->y_ppem == 0 )
1304 bsize->y_ppem = bsize->size;
1306 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1308 if ( resolution_x && resolution_y )
1309 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1311 bsize->x_ppem = bsize->y_ppem;
1314 /* set up charset */
1316 PCF_Property charset_registry = 0, charset_encoding = 0;
1319 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1320 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1322 if ( charset_registry && charset_registry->isString &&
1323 charset_encoding && charset_encoding->isString )
1325 if ( FT_STRDUP( face->charset_encoding,
1326 charset_encoding->value.atom ) ||
1327 FT_STRDUP( face->charset_registry,
1328 charset_registry->value.atom ) )
1337 /* This is done to respect the behaviour of the original */
1338 /* PCF font driver. */
1339 error = FT_THROW( Invalid_File_Format );