[CMAKE]
[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, 2008, 2009,
6 2010 by
7 Francesco Zappa Nardelli
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 */
27
28
29 #include <ft2build.h>
30
31 #include FT_INTERNAL_DEBUG_H
32 #include FT_INTERNAL_STREAM_H
33 #include FT_INTERNAL_OBJECTS_H
34
35 #include "pcf.h"
36 #include "pcfread.h"
37
38 #include "pcferror.h"
39
40
41 /*************************************************************************/
42 /* */
43 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
44 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
45 /* messages during execution. */
46 /* */
47 #undef FT_COMPONENT
48 #define FT_COMPONENT trace_pcfread
49
50
51 #ifdef FT_DEBUG_LEVEL_TRACE
52 static const char* const tableNames[] =
53 {
54 "prop", "accl", "mtrcs", "bmps", "imtrcs",
55 "enc", "swidth", "names", "accel"
56 };
57 #endif
58
59
60 static
61 const FT_Frame_Field pcf_toc_header[] =
62 {
63 #undef FT_STRUCTURE
64 #define FT_STRUCTURE PCF_TocRec
65
66 FT_FRAME_START( 8 ),
67 FT_FRAME_ULONG_LE( version ),
68 FT_FRAME_ULONG_LE( count ),
69 FT_FRAME_END
70 };
71
72
73 static
74 const FT_Frame_Field pcf_table_header[] =
75 {
76 #undef FT_STRUCTURE
77 #define FT_STRUCTURE PCF_TableRec
78
79 FT_FRAME_START( 16 ),
80 FT_FRAME_ULONG_LE( type ),
81 FT_FRAME_ULONG_LE( format ),
82 FT_FRAME_ULONG_LE( size ),
83 FT_FRAME_ULONG_LE( offset ),
84 FT_FRAME_END
85 };
86
87
88 static FT_Error
89 pcf_read_TOC( FT_Stream stream,
90 PCF_Face face )
91 {
92 FT_Error error;
93 PCF_Toc toc = &face->toc;
94 PCF_Table tables;
95
96 FT_Memory memory = FT_FACE(face)->memory;
97 FT_UInt n;
98
99
100 if ( FT_STREAM_SEEK ( 0 ) ||
101 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
102 return PCF_Err_Cannot_Open_Resource;
103
104 if ( toc->version != PCF_FILE_VERSION ||
105 toc->count > FT_ARRAY_MAX( face->toc.tables ) ||
106 toc->count == 0 )
107 return PCF_Err_Invalid_File_Format;
108
109 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
110 return PCF_Err_Out_Of_Memory;
111
112 tables = face->toc.tables;
113 for ( n = 0; n < toc->count; n++ )
114 {
115 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
116 goto Exit;
117 tables++;
118 }
119
120 /* Sort tables and check for overlaps. Because they are almost */
121 /* always ordered already, an in-place bubble sort with simultaneous */
122 /* boundary checking seems appropriate. */
123 tables = face->toc.tables;
124
125 for ( n = 0; n < toc->count - 1; n++ )
126 {
127 FT_UInt i, have_change;
128
129
130 have_change = 0;
131
132 for ( i = 0; i < toc->count - 1 - n; i++ )
133 {
134 PCF_TableRec tmp;
135
136
137 if ( tables[i].offset > tables[i + 1].offset )
138 {
139 tmp = tables[i];
140 tables[i] = tables[i + 1];
141 tables[i + 1] = tmp;
142
143 have_change = 1;
144 }
145
146 if ( ( tables[i].size > tables[i + 1].offset ) ||
147 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
148 return PCF_Err_Invalid_Offset;
149 }
150
151 if ( !have_change )
152 break;
153 }
154
155 #ifdef FT_DEBUG_LEVEL_TRACE
156
157 {
158 FT_UInt i, j;
159 const char* name = "?";
160
161
162 FT_TRACE4(( "pcf_read_TOC:\n" ));
163
164 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
165
166 tables = face->toc.tables;
167 for ( i = 0; i < toc->count; i++ )
168 {
169 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
170 j++ )
171 if ( tables[i].type == (FT_UInt)( 1 << j ) )
172 name = tableNames[j];
173
174 FT_TRACE4(( " %d: type=%s, format=0x%X, "
175 "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
176 i, name,
177 tables[i].format,
178 tables[i].size, tables[i].size,
179 tables[i].offset, tables[i].offset ));
180 }
181 }
182
183 #endif
184
185 return PCF_Err_Ok;
186
187 Exit:
188 FT_FREE( face->toc.tables );
189 return error;
190 }
191
192
193 #define PCF_METRIC_SIZE 12
194
195 static
196 const FT_Frame_Field pcf_metric_header[] =
197 {
198 #undef FT_STRUCTURE
199 #define FT_STRUCTURE PCF_MetricRec
200
201 FT_FRAME_START( PCF_METRIC_SIZE ),
202 FT_FRAME_SHORT_LE( leftSideBearing ),
203 FT_FRAME_SHORT_LE( rightSideBearing ),
204 FT_FRAME_SHORT_LE( characterWidth ),
205 FT_FRAME_SHORT_LE( ascent ),
206 FT_FRAME_SHORT_LE( descent ),
207 FT_FRAME_SHORT_LE( attributes ),
208 FT_FRAME_END
209 };
210
211
212 static
213 const FT_Frame_Field pcf_metric_msb_header[] =
214 {
215 #undef FT_STRUCTURE
216 #define FT_STRUCTURE PCF_MetricRec
217
218 FT_FRAME_START( PCF_METRIC_SIZE ),
219 FT_FRAME_SHORT( leftSideBearing ),
220 FT_FRAME_SHORT( rightSideBearing ),
221 FT_FRAME_SHORT( characterWidth ),
222 FT_FRAME_SHORT( ascent ),
223 FT_FRAME_SHORT( descent ),
224 FT_FRAME_SHORT( attributes ),
225 FT_FRAME_END
226 };
227
228
229 #define PCF_COMPRESSED_METRIC_SIZE 5
230
231 static
232 const FT_Frame_Field pcf_compressed_metric_header[] =
233 {
234 #undef FT_STRUCTURE
235 #define FT_STRUCTURE PCF_Compressed_MetricRec
236
237 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
238 FT_FRAME_BYTE( leftSideBearing ),
239 FT_FRAME_BYTE( rightSideBearing ),
240 FT_FRAME_BYTE( characterWidth ),
241 FT_FRAME_BYTE( ascent ),
242 FT_FRAME_BYTE( descent ),
243 FT_FRAME_END
244 };
245
246
247 static FT_Error
248 pcf_get_metric( FT_Stream stream,
249 FT_ULong format,
250 PCF_Metric metric )
251 {
252 FT_Error error = PCF_Err_Ok;
253
254
255 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
256 {
257 const FT_Frame_Field* fields;
258
259
260 /* parsing normal metrics */
261 fields = PCF_BYTE_ORDER( format ) == MSBFirst
262 ? pcf_metric_msb_header
263 : pcf_metric_header;
264
265 /* the following sets `error' but doesn't return in case of failure */
266 (void)FT_STREAM_READ_FIELDS( fields, metric );
267 }
268 else
269 {
270 PCF_Compressed_MetricRec compr;
271
272
273 /* parsing compressed metrics */
274 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
275 goto Exit;
276
277 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
278 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
279 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
280 metric->ascent = (FT_Short)( compr.ascent - 0x80 );
281 metric->descent = (FT_Short)( compr.descent - 0x80 );
282 metric->attributes = 0;
283 }
284
285 Exit:
286 return error;
287 }
288
289
290 static FT_Error
291 pcf_seek_to_table_type( FT_Stream stream,
292 PCF_Table tables,
293 FT_ULong ntables, /* same as PCF_Toc->count */
294 FT_ULong type,
295 FT_ULong *aformat,
296 FT_ULong *asize )
297 {
298 FT_Error error = PCF_Err_Invalid_File_Format;
299 FT_ULong 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_ULong ntables, /* same as PCF_Toc->count */
332 FT_ULong type )
333 {
334 FT_ULong 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_ULong 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 (truncate %d props)\n",
438 (int)nprops, nprops - (int)nprops ));
439
440 nprops = (int)nprops;
441
442 /* rough estimate */
443 if ( nprops > size / PCF_PROPERTY_SIZE )
444 {
445 error = PCF_Err_Invalid_Table;
446 goto Bail;
447 }
448
449 face->nprops = (int)nprops;
450
451 if ( FT_NEW_ARRAY( props, nprops ) )
452 goto Bail;
453
454 for ( i = 0; i < nprops; i++ )
455 {
456 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
457 {
458 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
459 goto Bail;
460 }
461 else
462 {
463 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
464 goto Bail;
465 }
466 }
467
468 /* pad the property array */
469 /* */
470 /* clever here - nprops is the same as the number of odd-units read, */
471 /* as only isStringProp are odd length (Keith Packard) */
472 /* */
473 if ( nprops & 3 )
474 {
475 i = 4 - ( nprops & 3 );
476 if ( FT_STREAM_SKIP( i ) )
477 {
478 error = PCF_Err_Invalid_Stream_Skip;
479 goto Bail;
480 }
481 }
482
483 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
484 (void)FT_READ_ULONG( string_size );
485 else
486 (void)FT_READ_ULONG_LE( string_size );
487 if ( error )
488 goto Bail;
489
490 FT_TRACE4(( " string_size = %ld\n", string_size ));
491
492 /* rough estimate */
493 if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
494 {
495 error = PCF_Err_Invalid_Table;
496 goto Bail;
497 }
498
499 if ( FT_NEW_ARRAY( strings, string_size ) )
500 goto Bail;
501
502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
503 if ( error )
504 goto Bail;
505
506 if ( FT_NEW_ARRAY( properties, nprops ) )
507 goto Bail;
508
509 face->properties = properties;
510
511 for ( i = 0; i < nprops; i++ )
512 {
513 FT_Long name_offset = props[i].name;
514
515
516 if ( ( name_offset < 0 ) ||
517 ( (FT_ULong)name_offset > string_size ) )
518 {
519 error = PCF_Err_Invalid_Offset;
520 goto Bail;
521 }
522
523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
524 goto Bail;
525
526 FT_TRACE4(( " %s:", properties[i].name ));
527
528 properties[i].isString = props[i].isString;
529
530 if ( props[i].isString )
531 {
532 FT_Long value_offset = props[i].value;
533
534
535 if ( ( value_offset < 0 ) ||
536 ( (FT_ULong)value_offset > string_size ) )
537 {
538 error = PCF_Err_Invalid_Offset;
539 goto Bail;
540 }
541
542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
543 goto Bail;
544
545 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
546 }
547 else
548 {
549 properties[i].value.l = props[i].value;
550
551 FT_TRACE4(( " %d\n", properties[i].value.l ));
552 }
553 }
554
555 error = PCF_Err_Ok;
556
557 Bail:
558 FT_FREE( props );
559 FT_FREE( strings );
560
561 return error;
562 }
563
564
565 static FT_Error
566 pcf_get_metrics( FT_Stream stream,
567 PCF_Face face )
568 {
569 FT_Error error = PCF_Err_Ok;
570 FT_Memory memory = FT_FACE(face)->memory;
571 FT_ULong format, size;
572 PCF_Metric metrics = 0;
573 FT_ULong nmetrics, i;
574
575
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;
584
585 if ( FT_READ_ULONG_LE( format ) )
586 goto Bail;
587
588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
590 return PCF_Err_Invalid_File_Format;
591
592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
593 {
594 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
595 (void)FT_READ_ULONG( nmetrics );
596 else
597 (void)FT_READ_ULONG_LE( nmetrics );
598 }
599 else
600 {
601 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
602 (void)FT_READ_USHORT( nmetrics );
603 else
604 (void)FT_READ_USHORT_LE( nmetrics );
605 }
606 if ( error )
607 return PCF_Err_Invalid_File_Format;
608
609 face->nmetrics = nmetrics;
610
611 if ( !nmetrics )
612 return PCF_Err_Invalid_Table;
613
614 FT_TRACE4(( "pcf_get_metrics:\n" ));
615
616 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
617
618 /* rough estimate */
619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
620 {
621 if ( nmetrics > size / PCF_METRIC_SIZE )
622 return PCF_Err_Invalid_Table;
623 }
624 else
625 {
626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
627 return PCF_Err_Invalid_Table;
628 }
629
630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
631 return PCF_Err_Out_Of_Memory;
632
633 metrics = face->metrics;
634 for ( i = 0; i < nmetrics; i++ )
635 {
636 error = pcf_get_metric( stream, format, metrics + i );
637
638 metrics[i].bits = 0;
639
640 FT_TRACE5(( " idx %d: width=%d, "
641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
642 i,
643 ( metrics + i )->characterWidth,
644 ( metrics + i )->leftSideBearing,
645 ( metrics + i )->rightSideBearing,
646 ( metrics + i )->ascent,
647 ( metrics + i )->descent,
648 ( metrics + i )->attributes ));
649
650 if ( error )
651 break;
652 }
653
654 if ( error )
655 FT_FREE( face->metrics );
656
657 Bail:
658 return error;
659 }
660
661
662 static FT_Error
663 pcf_get_bitmaps( FT_Stream stream,
664 PCF_Face face )
665 {
666 FT_Error error = PCF_Err_Ok;
667 FT_Memory memory = FT_FACE(face)->memory;
668 FT_Long* offsets;
669 FT_Long bitmapSizes[GLYPHPADOPTIONS];
670 FT_ULong format, size;
671 FT_ULong nbitmaps, i, sizebitmaps = 0;
672
673
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;
682
683 error = FT_Stream_EnterFrame( stream, 8 );
684 if ( error )
685 return error;
686
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();
692
693 FT_Stream_ExitFrame( stream );
694
695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
696 return PCF_Err_Invalid_File_Format;
697
698 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
699
700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
701
702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
704 return PCF_Err_Invalid_File_Format;
705
706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
707 return error;
708
709 for ( i = 0; i < nbitmaps; i++ )
710 {
711 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
712 (void)FT_READ_LONG( offsets[i] );
713 else
714 (void)FT_READ_LONG_LE( offsets[i] );
715
716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
717 i, offsets[i], offsets[i] ));
718 }
719 if ( error )
720 goto Bail;
721
722 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
723 {
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;
730
731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
732
733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
734 }
735
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 ));
740
741 FT_UNUSED( sizebitmaps ); /* only used for debugging */
742
743 for ( i = 0; i < nbitmaps; i++ )
744 {
745 /* rough estimate */
746 if ( ( offsets[i] < 0 ) ||
747 ( (FT_ULong)offsets[i] > size ) )
748 {
749 FT_TRACE0(( "pcf_get_bitmaps:"
750 " invalid offset to bitmap data of glyph %d\n", i ));
751 }
752 else
753 face->metrics[i].bits = stream->pos + offsets[i];
754 }
755
756 face->bitmapsFormat = format;
757
758 Bail:
759 FT_FREE( offsets );
760 return error;
761 }
762
763
764 static FT_Error
765 pcf_get_encodings( FT_Stream stream,
766 PCF_Face face )
767 {
768 FT_Error error = PCF_Err_Ok;
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;
775 PCF_Encoding tmpEncoding, encoding = 0;
776
777
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;
786
787 error = FT_Stream_EnterFrame( stream, 14 );
788 if ( error )
789 return error;
790
791 format = FT_GET_ULONG_LE();
792
793 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
794 {
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();
800 }
801 else
802 {
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();
808 }
809
810 FT_Stream_ExitFrame( stream );
811
812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
813 return PCF_Err_Invalid_File_Format;
814
815 FT_TRACE4(( "pdf_get_encodings:\n" ));
816
817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
818 firstCol, lastCol, firstRow, lastRow ));
819
820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
821
822 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
823 return PCF_Err_Out_Of_Memory;
824
825 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
826 if ( error )
827 goto Bail;
828
829 for ( i = 0, j = 0 ; i < nencoding; i++ )
830 {
831 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
832 encodingOffset = FT_GET_SHORT();
833 else
834 encodingOffset = FT_GET_SHORT_LE();
835
836 if ( encodingOffset != -1 )
837 {
838 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
839 firstRow ) * 256 ) +
840 ( ( i % ( lastCol - firstCol + 1 ) ) +
841 firstCol );
842
843 tmpEncoding[j].glyph = (FT_Short)encodingOffset;
844
845 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
846 tmpEncoding[j].enc, tmpEncoding[j].enc,
847 tmpEncoding[j].glyph ));
848
849 j++;
850 }
851 }
852 FT_Stream_ExitFrame( stream );
853
854 if ( FT_NEW_ARRAY( encoding, j ) )
855 goto Bail;
856
857 for ( i = 0; i < j; i++ )
858 {
859 encoding[i].enc = tmpEncoding[i].enc;
860 encoding[i].glyph = tmpEncoding[i].glyph;
861 }
862
863 face->nencodings = j;
864 face->encodings = encoding;
865 FT_FREE( tmpEncoding );
866
867 return error;
868
869 Bail:
870 FT_FREE( encoding );
871 FT_FREE( tmpEncoding );
872 return error;
873 }
874
875
876 static
877 const FT_Frame_Field pcf_accel_header[] =
878 {
879 #undef FT_STRUCTURE
880 #define FT_STRUCTURE PCF_AccelRec
881
882 FT_FRAME_START( 20 ),
883 FT_FRAME_BYTE ( noOverlap ),
884 FT_FRAME_BYTE ( constantMetrics ),
885 FT_FRAME_BYTE ( terminalFont ),
886 FT_FRAME_BYTE ( constantWidth ),
887 FT_FRAME_BYTE ( inkInside ),
888 FT_FRAME_BYTE ( inkMetrics ),
889 FT_FRAME_BYTE ( drawDirection ),
890 FT_FRAME_SKIP_BYTES( 1 ),
891 FT_FRAME_LONG_LE ( fontAscent ),
892 FT_FRAME_LONG_LE ( fontDescent ),
893 FT_FRAME_LONG_LE ( maxOverlap ),
894 FT_FRAME_END
895 };
896
897
898 static
899 const FT_Frame_Field pcf_accel_msb_header[] =
900 {
901 #undef FT_STRUCTURE
902 #define FT_STRUCTURE PCF_AccelRec
903
904 FT_FRAME_START( 20 ),
905 FT_FRAME_BYTE ( noOverlap ),
906 FT_FRAME_BYTE ( constantMetrics ),
907 FT_FRAME_BYTE ( terminalFont ),
908 FT_FRAME_BYTE ( constantWidth ),
909 FT_FRAME_BYTE ( inkInside ),
910 FT_FRAME_BYTE ( inkMetrics ),
911 FT_FRAME_BYTE ( drawDirection ),
912 FT_FRAME_SKIP_BYTES( 1 ),
913 FT_FRAME_LONG ( fontAscent ),
914 FT_FRAME_LONG ( fontDescent ),
915 FT_FRAME_LONG ( maxOverlap ),
916 FT_FRAME_END
917 };
918
919
920 static FT_Error
921 pcf_get_accel( FT_Stream stream,
922 PCF_Face face,
923 FT_ULong type )
924 {
925 FT_ULong format, size;
926 FT_Error error = PCF_Err_Ok;
927 PCF_Accel accel = &face->accel;
928
929
930 error = pcf_seek_to_table_type( stream,
931 face->toc.tables,
932 face->toc.count,
933 type,
934 &format,
935 &size );
936 if ( error )
937 goto Bail;
938
939 if ( FT_READ_ULONG_LE( format ) )
940 goto Bail;
941
942 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
943 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
944 goto Bail;
945
946 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
947 {
948 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
949 goto Bail;
950 }
951 else
952 {
953 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
954 goto Bail;
955 }
956
957 error = pcf_get_metric( stream,
958 format & ( ~PCF_FORMAT_MASK ),
959 &(accel->minbounds) );
960 if ( error )
961 goto Bail;
962
963 error = pcf_get_metric( stream,
964 format & ( ~PCF_FORMAT_MASK ),
965 &(accel->maxbounds) );
966 if ( error )
967 goto Bail;
968
969 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
970 {
971 error = pcf_get_metric( stream,
972 format & ( ~PCF_FORMAT_MASK ),
973 &(accel->ink_minbounds) );
974 if ( error )
975 goto Bail;
976
977 error = pcf_get_metric( stream,
978 format & ( ~PCF_FORMAT_MASK ),
979 &(accel->ink_maxbounds) );
980 if ( error )
981 goto Bail;
982 }
983 else
984 {
985 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
986 accel->ink_maxbounds = accel->maxbounds;
987 }
988
989 Bail:
990 return error;
991 }
992
993
994 static FT_Error
995 pcf_interpret_style( PCF_Face pcf )
996 {
997 FT_Error error = PCF_Err_Ok;
998 FT_Face face = FT_FACE( pcf );
999 FT_Memory memory = face->memory;
1000
1001 PCF_Property prop;
1002
1003 size_t nn, len;
1004 char* strings[4] = { NULL, NULL, NULL, NULL };
1005 size_t lengths[4];
1006
1007
1008 face->style_flags = 0;
1009
1010 prop = pcf_find_property( pcf, "SLANT" );
1011 if ( prop && prop->isString &&
1012 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1013 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1014 {
1015 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1016 strings[2] = ( *(prop->value.atom) == 'O' ||
1017 *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1018 : (char *)"Italic";
1019 }
1020
1021 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1022 if ( prop && prop->isString &&
1023 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1024 {
1025 face->style_flags |= FT_STYLE_FLAG_BOLD;
1026 strings[1] = (char *)"Bold";
1027 }
1028
1029 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1030 if ( prop && prop->isString &&
1031 *(prop->value.atom) &&
1032 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1033 strings[3] = (char *)(prop->value.atom);
1034
1035 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1036 if ( prop && prop->isString &&
1037 *(prop->value.atom) &&
1038 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1039 strings[0] = (char *)(prop->value.atom);
1040
1041 for ( len = 0, nn = 0; nn < 4; nn++ )
1042 {
1043 lengths[nn] = 0;
1044 if ( strings[nn] )
1045 {
1046 lengths[nn] = ft_strlen( strings[nn] );
1047 len += lengths[nn] + 1;
1048 }
1049 }
1050
1051 if ( len == 0 )
1052 {
1053 strings[0] = (char *)"Regular";
1054 lengths[0] = ft_strlen( strings[0] );
1055 len = lengths[0] + 1;
1056 }
1057
1058 {
1059 char* s;
1060
1061
1062 if ( FT_ALLOC( face->style_name, len ) )
1063 return error;
1064
1065 s = face->style_name;
1066
1067 for ( nn = 0; nn < 4; nn++ )
1068 {
1069 char* src = strings[nn];
1070
1071
1072 len = lengths[nn];
1073
1074 if ( src == NULL )
1075 continue;
1076
1077 /* separate elements with a space */
1078 if ( s != face->style_name )
1079 *s++ = ' ';
1080
1081 ft_memcpy( s, src, len );
1082
1083 /* need to convert spaces to dashes for */
1084 /* add_style_name and setwidth_name */
1085 if ( nn == 0 || nn == 3 )
1086 {
1087 size_t mm;
1088
1089
1090 for ( mm = 0; mm < len; mm++ )
1091 if (s[mm] == ' ')
1092 s[mm] = '-';
1093 }
1094
1095 s += len;
1096 }
1097 *s = 0;
1098 }
1099
1100 return error;
1101 }
1102
1103
1104 FT_LOCAL_DEF( FT_Error )
1105 pcf_load_font( FT_Stream stream,
1106 PCF_Face face )
1107 {
1108 FT_Error error = PCF_Err_Ok;
1109 FT_Memory memory = FT_FACE(face)->memory;
1110 FT_Bool hasBDFAccelerators;
1111
1112
1113 error = pcf_read_TOC( stream, face );
1114 if ( error )
1115 goto Exit;
1116
1117 error = pcf_get_properties( stream, face );
1118 if ( error )
1119 goto Exit;
1120
1121 /* Use the old accelerators if no BDF accelerators are in the file. */
1122 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1123 face->toc.count,
1124 PCF_BDF_ACCELERATORS );
1125 if ( !hasBDFAccelerators )
1126 {
1127 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1128 if ( error )
1129 goto Exit;
1130 }
1131
1132 /* metrics */
1133 error = pcf_get_metrics( stream, face );
1134 if ( error )
1135 goto Exit;
1136
1137 /* bitmaps */
1138 error = pcf_get_bitmaps( stream, face );
1139 if ( error )
1140 goto Exit;
1141
1142 /* encodings */
1143 error = pcf_get_encodings( stream, face );
1144 if ( error )
1145 goto Exit;
1146
1147 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1148 if ( hasBDFAccelerators )
1149 {
1150 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1151 if ( error )
1152 goto Exit;
1153 }
1154
1155 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1156
1157 /* now construct the face object */
1158 {
1159 FT_Face root = FT_FACE( face );
1160 PCF_Property prop;
1161
1162
1163 root->num_faces = 1;
1164 root->face_index = 0;
1165 root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1166 FT_FACE_FLAG_HORIZONTAL |
1167 FT_FACE_FLAG_FAST_GLYPHS;
1168
1169 if ( face->accel.constantWidth )
1170 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1171
1172 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1173 goto Exit;
1174
1175 prop = pcf_find_property( face, "FAMILY_NAME" );
1176 if ( prop && prop->isString )
1177 {
1178 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1179 goto Exit;
1180 }
1181 else
1182 root->family_name = NULL;
1183
1184 /*
1185 * Note: We shift all glyph indices by +1 since we must
1186 * respect the convention that glyph 0 always corresponds
1187 * to the `missing glyph'.
1188 *
1189 * This implies bumping the number of `available' glyphs by 1.
1190 */
1191 root->num_glyphs = face->nmetrics + 1;
1192
1193 root->num_fixed_sizes = 1;
1194 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1195 goto Exit;
1196
1197 {
1198 FT_Bitmap_Size* bsize = root->available_sizes;
1199 FT_Short resolution_x = 0, resolution_y = 0;
1200
1201
1202 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1203
1204 #if 0
1205 bsize->height = face->accel.maxbounds.ascent << 6;
1206 #endif
1207 bsize->height = (FT_Short)( face->accel.fontAscent +
1208 face->accel.fontDescent );
1209
1210 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1211 if ( prop )
1212 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1213 else
1214 bsize->width = (FT_Short)( bsize->height * 2/3 );
1215
1216 prop = pcf_find_property( face, "POINT_SIZE" );
1217 if ( prop )
1218 /* convert from 722.7 decipoints to 72 points per inch */
1219 bsize->size =
1220 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1221
1222 prop = pcf_find_property( face, "PIXEL_SIZE" );
1223 if ( prop )
1224 bsize->y_ppem = (FT_Short)prop->value.l << 6;
1225
1226 prop = pcf_find_property( face, "RESOLUTION_X" );
1227 if ( prop )
1228 resolution_x = (FT_Short)prop->value.l;
1229
1230 prop = pcf_find_property( face, "RESOLUTION_Y" );
1231 if ( prop )
1232 resolution_y = (FT_Short)prop->value.l;
1233
1234 if ( bsize->y_ppem == 0 )
1235 {
1236 bsize->y_ppem = bsize->size;
1237 if ( resolution_y )
1238 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1239 }
1240 if ( resolution_x && resolution_y )
1241 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1242 else
1243 bsize->x_ppem = bsize->y_ppem;
1244 }
1245
1246 /* set up charset */
1247 {
1248 PCF_Property charset_registry = 0, charset_encoding = 0;
1249
1250
1251 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1252 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1253
1254 if ( charset_registry && charset_registry->isString &&
1255 charset_encoding && charset_encoding->isString )
1256 {
1257 if ( FT_STRDUP( face->charset_encoding,
1258 charset_encoding->value.atom ) ||
1259 FT_STRDUP( face->charset_registry,
1260 charset_registry->value.atom ) )
1261 goto Exit;
1262 }
1263 }
1264 }
1265
1266 Exit:
1267 if ( error )
1268 {
1269 /* This is done to respect the behaviour of the original */
1270 /* PCF font driver. */
1271 error = PCF_Err_Invalid_File_Format;
1272 }
1273
1274 return error;
1275 }
1276
1277
1278 /* END */