start service tasks separately in-case platforms need to perform additional set-up...
[AROS.git] / workbench / libs / freetype / src / pcf / pcfread.c
blob3c1bb7dfa24348e3c4ccadce806047c7e3d1a959
1 /* pcfread.c
3 FreeType font driver for pcf fonts
5 Copyright 2000-2010, 2012, 2013 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 "pcfread.h"
37 #include "pcferror.h"
40 /*************************************************************************/
41 /* */
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. */
45 /* */
46 #undef FT_COMPONENT
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"
56 #endif
59 static
60 const FT_Frame_Field pcf_toc_header[] =
62 #undef FT_STRUCTURE
63 #define FT_STRUCTURE PCF_TocRec
65 FT_FRAME_START( 8 ),
66 FT_FRAME_ULONG_LE( version ),
67 FT_FRAME_ULONG_LE( count ),
68 FT_FRAME_END
72 static
73 const FT_Frame_Field pcf_table_header[] =
75 #undef FT_STRUCTURE
76 #define FT_STRUCTURE PCF_TableRec
78 FT_FRAME_START( 16 ),
79 FT_FRAME_ULONG_LE( type ),
80 FT_FRAME_ULONG_LE( format ),
81 FT_FRAME_ULONG_LE( size ),
82 FT_FRAME_ULONG_LE( offset ),
83 FT_FRAME_END
87 static FT_Error
88 pcf_read_TOC( FT_Stream stream,
89 PCF_Face face )
91 FT_Error error;
92 PCF_Toc toc = &face->toc;
93 PCF_Table tables;
95 FT_Memory memory = FT_FACE( face )->memory;
96 FT_UInt n;
99 if ( FT_STREAM_SEEK ( 0 ) ||
100 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
101 return FT_THROW( Cannot_Open_Resource );
103 if ( toc->version != PCF_FILE_VERSION ||
104 toc->count > FT_ARRAY_MAX( face->toc.tables ) ||
105 toc->count == 0 )
106 return FT_THROW( Invalid_File_Format );
108 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
109 return FT_THROW( Out_Of_Memory );
111 tables = face->toc.tables;
112 for ( n = 0; n < toc->count; n++ )
114 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
115 goto Exit;
116 tables++;
119 /* Sort tables and check for overlaps. Because they are almost */
120 /* always ordered already, an in-place bubble sort with simultaneous */
121 /* boundary checking seems appropriate. */
122 tables = face->toc.tables;
124 for ( n = 0; n < toc->count - 1; n++ )
126 FT_UInt i, have_change;
129 have_change = 0;
131 for ( i = 0; i < toc->count - 1 - n; i++ )
133 PCF_TableRec tmp;
136 if ( tables[i].offset > tables[i + 1].offset )
138 tmp = tables[i];
139 tables[i] = tables[i + 1];
140 tables[i + 1] = tmp;
142 have_change = 1;
145 if ( ( tables[i].size > tables[i + 1].offset ) ||
146 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
147 return FT_THROW( Invalid_Offset );
150 if ( !have_change )
151 break;
154 #ifdef FT_DEBUG_LEVEL_TRACE
157 FT_UInt i, j;
158 const char* name = "?";
161 FT_TRACE4(( "pcf_read_TOC:\n" ));
163 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
165 tables = face->toc.tables;
166 for ( i = 0; i < toc->count; i++ )
168 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
169 j++ )
170 if ( tables[i].type == (FT_UInt)( 1 << j ) )
171 name = tableNames[j];
173 FT_TRACE4(( " %d: type=%s, format=0x%X, "
174 "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
175 i, name,
176 tables[i].format,
177 tables[i].size, tables[i].size,
178 tables[i].offset, tables[i].offset ));
182 #endif
184 return FT_Err_Ok;
186 Exit:
187 FT_FREE( face->toc.tables );
188 return error;
192 #define PCF_METRIC_SIZE 12
194 static
195 const FT_Frame_Field pcf_metric_header[] =
197 #undef FT_STRUCTURE
198 #define FT_STRUCTURE PCF_MetricRec
200 FT_FRAME_START( PCF_METRIC_SIZE ),
201 FT_FRAME_SHORT_LE( leftSideBearing ),
202 FT_FRAME_SHORT_LE( rightSideBearing ),
203 FT_FRAME_SHORT_LE( characterWidth ),
204 FT_FRAME_SHORT_LE( ascent ),
205 FT_FRAME_SHORT_LE( descent ),
206 FT_FRAME_SHORT_LE( attributes ),
207 FT_FRAME_END
211 static
212 const FT_Frame_Field pcf_metric_msb_header[] =
214 #undef FT_STRUCTURE
215 #define FT_STRUCTURE PCF_MetricRec
217 FT_FRAME_START( PCF_METRIC_SIZE ),
218 FT_FRAME_SHORT( leftSideBearing ),
219 FT_FRAME_SHORT( rightSideBearing ),
220 FT_FRAME_SHORT( characterWidth ),
221 FT_FRAME_SHORT( ascent ),
222 FT_FRAME_SHORT( descent ),
223 FT_FRAME_SHORT( attributes ),
224 FT_FRAME_END
228 #define PCF_COMPRESSED_METRIC_SIZE 5
230 static
231 const FT_Frame_Field pcf_compressed_metric_header[] =
233 #undef FT_STRUCTURE
234 #define FT_STRUCTURE PCF_Compressed_MetricRec
236 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
237 FT_FRAME_BYTE( leftSideBearing ),
238 FT_FRAME_BYTE( rightSideBearing ),
239 FT_FRAME_BYTE( characterWidth ),
240 FT_FRAME_BYTE( ascent ),
241 FT_FRAME_BYTE( descent ),
242 FT_FRAME_END
246 static FT_Error
247 pcf_get_metric( FT_Stream stream,
248 FT_ULong format,
249 PCF_Metric metric )
251 FT_Error error = FT_Err_Ok;
254 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
256 const FT_Frame_Field* fields;
259 /* parsing normal metrics */
260 fields = PCF_BYTE_ORDER( format ) == MSBFirst
261 ? pcf_metric_msb_header
262 : pcf_metric_header;
264 /* the following sets `error' but doesn't return in case of failure */
265 (void)FT_STREAM_READ_FIELDS( fields, metric );
267 else
269 PCF_Compressed_MetricRec compr;
272 /* parsing compressed metrics */
273 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
274 goto Exit;
276 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
277 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
278 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
279 metric->ascent = (FT_Short)( compr.ascent - 0x80 );
280 metric->descent = (FT_Short)( compr.descent - 0x80 );
281 metric->attributes = 0;
284 Exit:
285 return error;
289 static FT_Error
290 pcf_seek_to_table_type( FT_Stream stream,
291 PCF_Table tables,
292 FT_ULong ntables, /* same as PCF_Toc->count */
293 FT_ULong type,
294 FT_ULong *aformat,
295 FT_ULong *asize )
297 FT_Error error = FT_ERR( Invalid_File_Format );
298 FT_ULong i;
301 for ( i = 0; i < ntables; i++ )
302 if ( tables[i].type == type )
304 if ( stream->pos > tables[i].offset )
306 error = FT_THROW( Invalid_Stream_Skip );
307 goto Fail;
310 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
312 error = FT_THROW( Invalid_Stream_Skip );
313 goto Fail;
316 *asize = tables[i].size;
317 *aformat = tables[i].format;
319 return FT_Err_Ok;
322 Fail:
323 *asize = 0;
324 return error;
328 static FT_Bool
329 pcf_has_table_type( PCF_Table tables,
330 FT_ULong ntables, /* same as PCF_Toc->count */
331 FT_ULong type )
333 FT_ULong i;
336 for ( i = 0; i < ntables; i++ )
337 if ( tables[i].type == type )
338 return TRUE;
340 return FALSE;
344 #define PCF_PROPERTY_SIZE 9
346 static
347 const FT_Frame_Field pcf_property_header[] =
349 #undef FT_STRUCTURE
350 #define FT_STRUCTURE PCF_ParsePropertyRec
352 FT_FRAME_START( PCF_PROPERTY_SIZE ),
353 FT_FRAME_LONG_LE( name ),
354 FT_FRAME_BYTE ( isString ),
355 FT_FRAME_LONG_LE( value ),
356 FT_FRAME_END
360 static
361 const FT_Frame_Field pcf_property_msb_header[] =
363 #undef FT_STRUCTURE
364 #define FT_STRUCTURE PCF_ParsePropertyRec
366 FT_FRAME_START( PCF_PROPERTY_SIZE ),
367 FT_FRAME_LONG( name ),
368 FT_FRAME_BYTE( isString ),
369 FT_FRAME_LONG( value ),
370 FT_FRAME_END
374 FT_LOCAL_DEF( PCF_Property )
375 pcf_find_property( PCF_Face face,
376 const FT_String* prop )
378 PCF_Property properties = face->properties;
379 FT_Bool found = 0;
380 int i;
383 for ( i = 0 ; i < face->nprops && !found; i++ )
385 if ( !ft_strcmp( properties[i].name, prop ) )
386 found = 1;
389 if ( found )
390 return properties + i - 1;
391 else
392 return NULL;
396 static FT_Error
397 pcf_get_properties( FT_Stream stream,
398 PCF_Face face )
400 PCF_ParseProperty props = 0;
401 PCF_Property properties = NULL;
402 FT_ULong nprops, i;
403 FT_ULong format, size;
404 FT_Error error;
405 FT_Memory memory = FT_FACE( face )->memory;
406 FT_ULong string_size;
407 FT_String* strings = 0;
410 error = pcf_seek_to_table_type( stream,
411 face->toc.tables,
412 face->toc.count,
413 PCF_PROPERTIES,
414 &format,
415 &size );
416 if ( error )
417 goto Bail;
419 if ( FT_READ_ULONG_LE( format ) )
420 goto Bail;
422 FT_TRACE4(( "pcf_get_properties:\n" ));
424 FT_TRACE4(( " format = %ld\n", format ));
426 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
427 goto Bail;
429 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
430 (void)FT_READ_ULONG( nprops );
431 else
432 (void)FT_READ_ULONG_LE( nprops );
433 if ( error )
434 goto Bail;
436 FT_TRACE4(( " nprop = %d (truncate %d props)\n",
437 (int)nprops, nprops - (int)nprops ));
439 nprops = (int)nprops;
441 /* rough estimate */
442 if ( nprops > size / PCF_PROPERTY_SIZE )
444 error = FT_THROW( Invalid_Table );
445 goto Bail;
448 face->nprops = (int)nprops;
450 if ( FT_NEW_ARRAY( props, nprops ) )
451 goto Bail;
453 for ( i = 0; i < nprops; i++ )
455 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
457 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
458 goto Bail;
460 else
462 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
463 goto Bail;
467 /* pad the property array */
468 /* */
469 /* clever here - nprops is the same as the number of odd-units read, */
470 /* as only isStringProp are odd length (Keith Packard) */
471 /* */
472 if ( nprops & 3 )
474 i = 4 - ( nprops & 3 );
475 if ( FT_STREAM_SKIP( i ) )
477 error = FT_THROW( Invalid_Stream_Skip );
478 goto Bail;
482 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
483 (void)FT_READ_ULONG( string_size );
484 else
485 (void)FT_READ_ULONG_LE( string_size );
486 if ( error )
487 goto Bail;
489 FT_TRACE4(( " string_size = %ld\n", string_size ));
491 /* rough estimate */
492 if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
494 error = FT_THROW( Invalid_Table );
495 goto Bail;
498 /* allocate one more byte so that we have a final null byte */
499 if ( FT_NEW_ARRAY( strings, string_size + 1 ) )
500 goto Bail;
502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
503 if ( error )
504 goto Bail;
506 if ( FT_NEW_ARRAY( properties, nprops ) )
507 goto Bail;
509 face->properties = properties;
511 for ( i = 0; i < nprops; i++ )
513 FT_Long name_offset = props[i].name;
516 if ( ( name_offset < 0 ) ||
517 ( (FT_ULong)name_offset > string_size ) )
519 error = FT_THROW( Invalid_Offset );
520 goto Bail;
523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
524 goto Bail;
526 FT_TRACE4(( " %s:", properties[i].name ));
528 properties[i].isString = props[i].isString;
530 if ( props[i].isString )
532 FT_Long value_offset = props[i].value;
535 if ( ( value_offset < 0 ) ||
536 ( (FT_ULong)value_offset > string_size ) )
538 error = FT_THROW( Invalid_Offset );
539 goto Bail;
542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
543 goto Bail;
545 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
547 else
549 properties[i].value.l = props[i].value;
551 FT_TRACE4(( " %d\n", properties[i].value.l ));
555 error = FT_Err_Ok;
557 Bail:
558 FT_FREE( props );
559 FT_FREE( strings );
561 return error;
565 static FT_Error
566 pcf_get_metrics( FT_Stream stream,
567 PCF_Face face )
569 FT_Error error;
570 FT_Memory memory = FT_FACE( face )->memory;
571 FT_ULong format, size;
572 PCF_Metric metrics = 0;
573 FT_ULong nmetrics, i;
576 error = pcf_seek_to_table_type( stream,
577 face->toc.tables,
578 face->toc.count,
579 PCF_METRICS,
580 &format,
581 &size );
582 if ( error )
583 return error;
585 if ( FT_READ_ULONG_LE( format ) )
586 goto Bail;
588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
590 return FT_THROW( Invalid_File_Format );
592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
594 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
595 (void)FT_READ_ULONG( nmetrics );
596 else
597 (void)FT_READ_ULONG_LE( nmetrics );
599 else
601 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
602 (void)FT_READ_USHORT( nmetrics );
603 else
604 (void)FT_READ_USHORT_LE( nmetrics );
606 if ( error )
607 return FT_THROW( Invalid_File_Format );
609 face->nmetrics = nmetrics;
611 if ( !nmetrics )
612 return FT_THROW( Invalid_Table );
614 FT_TRACE4(( "pcf_get_metrics:\n" ));
616 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
618 /* rough estimate */
619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
621 if ( nmetrics > size / PCF_METRIC_SIZE )
622 return FT_THROW( Invalid_Table );
624 else
626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
627 return FT_THROW( Invalid_Table );
630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
631 return FT_THROW( Out_Of_Memory );
633 metrics = face->metrics;
634 for ( i = 0; i < nmetrics; i++ )
636 error = pcf_get_metric( stream, format, metrics + i );
638 metrics[i].bits = 0;
640 FT_TRACE5(( " idx %d: width=%d, "
641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
643 ( metrics + i )->characterWidth,
644 ( metrics + i )->leftSideBearing,
645 ( metrics + i )->rightSideBearing,
646 ( metrics + i )->ascent,
647 ( metrics + i )->descent,
648 ( metrics + i )->attributes ));
650 if ( error )
651 break;
654 if ( error )
655 FT_FREE( face->metrics );
657 Bail:
658 return error;
662 static FT_Error
663 pcf_get_bitmaps( FT_Stream stream,
664 PCF_Face face )
666 FT_Error error;
667 FT_Memory memory = FT_FACE( face )->memory;
668 FT_Long* offsets = NULL;
669 FT_Long bitmapSizes[GLYPHPADOPTIONS];
670 FT_ULong format, size;
671 FT_ULong nbitmaps, i, sizebitmaps = 0;
674 error = pcf_seek_to_table_type( stream,
675 face->toc.tables,
676 face->toc.count,
677 PCF_BITMAPS,
678 &format,
679 &size );
680 if ( error )
681 return error;
683 error = FT_Stream_EnterFrame( stream, 8 );
684 if ( error )
685 return error;
687 format = FT_GET_ULONG_LE();
688 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
689 nbitmaps = FT_GET_ULONG();
690 else
691 nbitmaps = FT_GET_ULONG_LE();
693 FT_Stream_ExitFrame( stream );
695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
696 return FT_THROW( Invalid_File_Format );
698 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
704 return FT_THROW( Invalid_File_Format );
706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
707 return error;
709 for ( i = 0; i < nbitmaps; i++ )
711 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
712 (void)FT_READ_LONG( offsets[i] );
713 else
714 (void)FT_READ_LONG_LE( offsets[i] );
716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
717 i, offsets[i], offsets[i] ));
719 if ( error )
720 goto Bail;
722 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
724 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
725 (void)FT_READ_LONG( bitmapSizes[i] );
726 else
727 (void)FT_READ_LONG_LE( bitmapSizes[i] );
728 if ( error )
729 goto Bail;
731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
736 FT_TRACE4(( " %d bitmaps, padding index %ld\n",
737 nbitmaps,
738 PCF_GLYPH_PAD_INDEX( format ) ));
739 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps ));
741 FT_UNUSED( sizebitmaps ); /* only used for debugging */
743 for ( i = 0; i < nbitmaps; i++ )
745 /* rough estimate */
746 if ( ( offsets[i] < 0 ) ||
747 ( (FT_ULong)offsets[i] > size ) )
749 FT_TRACE0(( "pcf_get_bitmaps:"
750 " invalid offset to bitmap data of glyph %d\n", i ));
752 else
753 face->metrics[i].bits = stream->pos + offsets[i];
756 face->bitmapsFormat = format;
758 Bail:
759 FT_FREE( offsets );
760 return error;
764 static FT_Error
765 pcf_get_encodings( FT_Stream stream,
766 PCF_Face face )
768 FT_Error error;
769 FT_Memory memory = FT_FACE( face )->memory;
770 FT_ULong format, size;
771 int firstCol, lastCol;
772 int firstRow, lastRow;
773 int nencoding, encodingOffset;
774 int i, j, k;
775 PCF_Encoding encoding = NULL;
778 error = pcf_seek_to_table_type( stream,
779 face->toc.tables,
780 face->toc.count,
781 PCF_BDF_ENCODINGS,
782 &format,
783 &size );
784 if ( error )
785 return error;
787 error = FT_Stream_EnterFrame( stream, 14 );
788 if ( error )
789 return error;
791 format = FT_GET_ULONG_LE();
793 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
795 firstCol = FT_GET_SHORT();
796 lastCol = FT_GET_SHORT();
797 firstRow = FT_GET_SHORT();
798 lastRow = FT_GET_SHORT();
799 face->defaultChar = FT_GET_SHORT();
801 else
803 firstCol = FT_GET_SHORT_LE();
804 lastCol = FT_GET_SHORT_LE();
805 firstRow = FT_GET_SHORT_LE();
806 lastRow = FT_GET_SHORT_LE();
807 face->defaultChar = FT_GET_SHORT_LE();
810 FT_Stream_ExitFrame( stream );
812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
813 return FT_THROW( Invalid_File_Format );
815 FT_TRACE4(( "pdf_get_encodings:\n" ));
817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
818 firstCol, lastCol, firstRow, lastRow ));
820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
822 if ( FT_NEW_ARRAY( encoding, nencoding ) )
823 return FT_THROW( Out_Of_Memory );
825 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
826 if ( error )
827 goto Bail;
829 k = 0;
830 for ( i = firstRow; i <= lastRow; i++ )
832 for ( j = firstCol; j <= lastCol; j++ )
834 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
835 encodingOffset = FT_GET_SHORT();
836 else
837 encodingOffset = FT_GET_SHORT_LE();
839 if ( encodingOffset != -1 )
841 encoding[k].enc = i * 256 + j;
842 encoding[k].glyph = (FT_Short)encodingOffset;
844 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
845 encoding[k].enc, encoding[k].enc, encoding[k].glyph ));
847 k++;
851 FT_Stream_ExitFrame( stream );
853 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) )
854 goto Bail;
856 face->nencodings = k;
857 face->encodings = encoding;
859 return error;
861 Bail:
862 FT_FREE( encoding );
863 return error;
867 static
868 const FT_Frame_Field pcf_accel_header[] =
870 #undef FT_STRUCTURE
871 #define FT_STRUCTURE PCF_AccelRec
873 FT_FRAME_START( 20 ),
874 FT_FRAME_BYTE ( noOverlap ),
875 FT_FRAME_BYTE ( constantMetrics ),
876 FT_FRAME_BYTE ( terminalFont ),
877 FT_FRAME_BYTE ( constantWidth ),
878 FT_FRAME_BYTE ( inkInside ),
879 FT_FRAME_BYTE ( inkMetrics ),
880 FT_FRAME_BYTE ( drawDirection ),
881 FT_FRAME_SKIP_BYTES( 1 ),
882 FT_FRAME_LONG_LE ( fontAscent ),
883 FT_FRAME_LONG_LE ( fontDescent ),
884 FT_FRAME_LONG_LE ( maxOverlap ),
885 FT_FRAME_END
889 static
890 const FT_Frame_Field pcf_accel_msb_header[] =
892 #undef FT_STRUCTURE
893 #define FT_STRUCTURE PCF_AccelRec
895 FT_FRAME_START( 20 ),
896 FT_FRAME_BYTE ( noOverlap ),
897 FT_FRAME_BYTE ( constantMetrics ),
898 FT_FRAME_BYTE ( terminalFont ),
899 FT_FRAME_BYTE ( constantWidth ),
900 FT_FRAME_BYTE ( inkInside ),
901 FT_FRAME_BYTE ( inkMetrics ),
902 FT_FRAME_BYTE ( drawDirection ),
903 FT_FRAME_SKIP_BYTES( 1 ),
904 FT_FRAME_LONG ( fontAscent ),
905 FT_FRAME_LONG ( fontDescent ),
906 FT_FRAME_LONG ( maxOverlap ),
907 FT_FRAME_END
911 static FT_Error
912 pcf_get_accel( FT_Stream stream,
913 PCF_Face face,
914 FT_ULong type )
916 FT_ULong format, size;
917 FT_Error error;
918 PCF_Accel accel = &face->accel;
921 error = pcf_seek_to_table_type( stream,
922 face->toc.tables,
923 face->toc.count,
924 type,
925 &format,
926 &size );
927 if ( error )
928 goto Bail;
930 if ( FT_READ_ULONG_LE( format ) )
931 goto Bail;
933 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
934 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
935 goto Bail;
937 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
939 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
940 goto Bail;
942 else
944 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
945 goto Bail;
948 error = pcf_get_metric( stream,
949 format & ( ~PCF_FORMAT_MASK ),
950 &(accel->minbounds) );
951 if ( error )
952 goto Bail;
954 error = pcf_get_metric( stream,
955 format & ( ~PCF_FORMAT_MASK ),
956 &(accel->maxbounds) );
957 if ( error )
958 goto Bail;
960 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
962 error = pcf_get_metric( stream,
963 format & ( ~PCF_FORMAT_MASK ),
964 &(accel->ink_minbounds) );
965 if ( error )
966 goto Bail;
968 error = pcf_get_metric( stream,
969 format & ( ~PCF_FORMAT_MASK ),
970 &(accel->ink_maxbounds) );
971 if ( error )
972 goto Bail;
974 else
976 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
977 accel->ink_maxbounds = accel->maxbounds;
980 Bail:
981 return error;
985 static FT_Error
986 pcf_interpret_style( PCF_Face pcf )
988 FT_Error error = FT_Err_Ok;
989 FT_Face face = FT_FACE( pcf );
990 FT_Memory memory = face->memory;
992 PCF_Property prop;
994 size_t nn, len;
995 char* strings[4] = { NULL, NULL, NULL, NULL };
996 size_t lengths[4];
999 face->style_flags = 0;
1001 prop = pcf_find_property( pcf, "SLANT" );
1002 if ( prop && prop->isString &&
1003 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1004 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1006 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1007 strings[2] = ( *(prop->value.atom) == 'O' ||
1008 *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1009 : (char *)"Italic";
1012 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1013 if ( prop && prop->isString &&
1014 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1016 face->style_flags |= FT_STYLE_FLAG_BOLD;
1017 strings[1] = (char*)"Bold";
1020 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1021 if ( prop && prop->isString &&
1022 *(prop->value.atom) &&
1023 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1024 strings[3] = (char*)( prop->value.atom );
1026 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1027 if ( prop && prop->isString &&
1028 *(prop->value.atom) &&
1029 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1030 strings[0] = (char*)( prop->value.atom );
1032 for ( len = 0, nn = 0; nn < 4; nn++ )
1034 lengths[nn] = 0;
1035 if ( strings[nn] )
1037 lengths[nn] = ft_strlen( strings[nn] );
1038 len += lengths[nn] + 1;
1042 if ( len == 0 )
1044 strings[0] = (char*)"Regular";
1045 lengths[0] = ft_strlen( strings[0] );
1046 len = lengths[0] + 1;
1050 char* s;
1053 if ( FT_ALLOC( face->style_name, len ) )
1054 return error;
1056 s = face->style_name;
1058 for ( nn = 0; nn < 4; nn++ )
1060 char* src = strings[nn];
1063 len = lengths[nn];
1065 if ( src == NULL )
1066 continue;
1068 /* separate elements with a space */
1069 if ( s != face->style_name )
1070 *s++ = ' ';
1072 ft_memcpy( s, src, len );
1074 /* need to convert spaces to dashes for */
1075 /* add_style_name and setwidth_name */
1076 if ( nn == 0 || nn == 3 )
1078 size_t mm;
1081 for ( mm = 0; mm < len; mm++ )
1082 if ( s[mm] == ' ' )
1083 s[mm] = '-';
1086 s += len;
1088 *s = 0;
1091 return error;
1095 FT_LOCAL_DEF( FT_Error )
1096 pcf_load_font( FT_Stream stream,
1097 PCF_Face face )
1099 FT_Error error = FT_Err_Ok;
1100 FT_Memory memory = FT_FACE( face )->memory;
1101 FT_Bool hasBDFAccelerators;
1104 error = pcf_read_TOC( stream, face );
1105 if ( error )
1106 goto Exit;
1108 error = pcf_get_properties( stream, face );
1109 if ( error )
1110 goto Exit;
1112 /* Use the old accelerators if no BDF accelerators are in the file. */
1113 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1114 face->toc.count,
1115 PCF_BDF_ACCELERATORS );
1116 if ( !hasBDFAccelerators )
1118 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1119 if ( error )
1120 goto Exit;
1123 /* metrics */
1124 error = pcf_get_metrics( stream, face );
1125 if ( error )
1126 goto Exit;
1128 /* bitmaps */
1129 error = pcf_get_bitmaps( stream, face );
1130 if ( error )
1131 goto Exit;
1133 /* encodings */
1134 error = pcf_get_encodings( stream, face );
1135 if ( error )
1136 goto Exit;
1138 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1139 if ( hasBDFAccelerators )
1141 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1142 if ( error )
1143 goto Exit;
1146 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1148 /* now construct the face object */
1150 FT_Face root = FT_FACE( face );
1151 PCF_Property prop;
1154 root->num_faces = 1;
1155 root->face_index = 0;
1156 root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1157 FT_FACE_FLAG_HORIZONTAL |
1158 FT_FACE_FLAG_FAST_GLYPHS;
1160 if ( face->accel.constantWidth )
1161 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1163 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1164 goto Exit;
1166 prop = pcf_find_property( face, "FAMILY_NAME" );
1167 if ( prop && prop->isString )
1169 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1170 goto Exit;
1172 else
1173 root->family_name = NULL;
1176 * Note: We shift all glyph indices by +1 since we must
1177 * respect the convention that glyph 0 always corresponds
1178 * to the `missing glyph'.
1180 * This implies bumping the number of `available' glyphs by 1.
1182 root->num_glyphs = face->nmetrics + 1;
1184 root->num_fixed_sizes = 1;
1185 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1186 goto Exit;
1189 FT_Bitmap_Size* bsize = root->available_sizes;
1190 FT_Short resolution_x = 0, resolution_y = 0;
1193 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1195 #if 0
1196 bsize->height = face->accel.maxbounds.ascent << 6;
1197 #endif
1198 bsize->height = (FT_Short)( face->accel.fontAscent +
1199 face->accel.fontDescent );
1201 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1202 if ( prop )
1203 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1204 else
1205 bsize->width = (FT_Short)( bsize->height * 2/3 );
1207 prop = pcf_find_property( face, "POINT_SIZE" );
1208 if ( prop )
1209 /* convert from 722.7 decipoints to 72 points per inch */
1210 bsize->size =
1211 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1213 prop = pcf_find_property( face, "PIXEL_SIZE" );
1214 if ( prop )
1215 bsize->y_ppem = (FT_Short)prop->value.l << 6;
1217 prop = pcf_find_property( face, "RESOLUTION_X" );
1218 if ( prop )
1219 resolution_x = (FT_Short)prop->value.l;
1221 prop = pcf_find_property( face, "RESOLUTION_Y" );
1222 if ( prop )
1223 resolution_y = (FT_Short)prop->value.l;
1225 if ( bsize->y_ppem == 0 )
1227 bsize->y_ppem = bsize->size;
1228 if ( resolution_y )
1229 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1231 if ( resolution_x && resolution_y )
1232 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1233 else
1234 bsize->x_ppem = bsize->y_ppem;
1237 /* set up charset */
1239 PCF_Property charset_registry = 0, charset_encoding = 0;
1242 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1243 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1245 if ( charset_registry && charset_registry->isString &&
1246 charset_encoding && charset_encoding->isString )
1248 if ( FT_STRDUP( face->charset_encoding,
1249 charset_encoding->value.atom ) ||
1250 FT_STRDUP( face->charset_registry,
1251 charset_registry->value.atom ) )
1252 goto Exit;
1257 Exit:
1258 if ( error )
1260 /* This is done to respect the behaviour of the original */
1261 /* PCF font driver. */
1262 error = FT_THROW( Invalid_File_Format );
1265 return error;
1269 /* END */