Sync with trunk (r47116), hopefully without breaking anything.
[reactos.git] / lib / 3rdparty / freetype / src / pcf / pcfread.c
1 /* pcfread.c
2
3 FreeType font driver for pcf fonts
4
5 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by
6 Francesco Zappa Nardelli
7
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:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
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.
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 #if defined( 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 #if defined( 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 */