Create a branch for cmake bringup.
[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 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 "pcfread.h"
36
37 #include "pcferror.h"
38
39
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
48
49
50 #ifdef FT_DEBUG_LEVEL_TRACE
51 static const char* const tableNames[] =
52 {
53 "prop", "accl", "mtrcs", "bmps", "imtrcs",
54 "enc", "swidth", "names", "accel"
55 };
56 #endif
57
58
59 static
60 const FT_Frame_Field pcf_toc_header[] =
61 {
62 #undef FT_STRUCTURE
63 #define FT_STRUCTURE PCF_TocRec
64
65 FT_FRAME_START( 8 ),
66 FT_FRAME_ULONG_LE( version ),
67 FT_FRAME_ULONG_LE( count ),
68 FT_FRAME_END
69 };
70
71
72 static
73 const FT_Frame_Field pcf_table_header[] =
74 {
75 #undef FT_STRUCTURE
76 #define FT_STRUCTURE PCF_TableRec
77
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
84 };
85
86
87 static FT_Error
88 pcf_read_TOC( FT_Stream stream,
89 PCF_Face face )
90 {
91 FT_Error error;
92 PCF_Toc toc = &face->toc;
93 PCF_Table tables;
94
95 FT_Memory memory = FT_FACE(face)->memory;
96 FT_UInt n;
97
98
99 if ( FT_STREAM_SEEK ( 0 ) ||
100 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
101 return PCF_Err_Cannot_Open_Resource;
102
103 if ( toc->version != PCF_FILE_VERSION ||
104 toc->count > FT_ARRAY_MAX( face->toc.tables ) ||
105 toc->count == 0 )
106 return PCF_Err_Invalid_File_Format;
107
108 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
109 return PCF_Err_Out_Of_Memory;
110
111 tables = face->toc.tables;
112 for ( n = 0; n < toc->count; n++ )
113 {
114 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
115 goto Exit;
116 tables++;
117 }
118
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;
123
124 for ( n = 0; n < toc->count - 1; n++ )
125 {
126 FT_UInt i, have_change;
127
128
129 have_change = 0;
130
131 for ( i = 0; i < toc->count - 1 - n; i++ )
132 {
133 PCF_TableRec tmp;
134
135
136 if ( tables[i].offset > tables[i + 1].offset )
137 {
138 tmp = tables[i];
139 tables[i] = tables[i + 1];
140 tables[i + 1] = tmp;
141
142 have_change = 1;
143 }
144
145 if ( ( tables[i].size > tables[i + 1].offset ) ||
146 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
147 return PCF_Err_Invalid_Offset;
148 }
149
150 if ( !have_change )
151 break;
152 }
153
154 #ifdef FT_DEBUG_LEVEL_TRACE
155
156 {
157 FT_UInt i, j;
158 const char* name = "?";
159
160
161 FT_TRACE4(( "pcf_read_TOC:\n" ));
162
163 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
164
165 tables = face->toc.tables;
166 for ( i = 0; i < toc->count; i++ )
167 {
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];
172
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 ));
179 }
180 }
181
182 #endif
183
184 return PCF_Err_Ok;
185
186 Exit:
187 FT_FREE( face->toc.tables );
188 return error;
189 }
190
191
192 #define PCF_METRIC_SIZE 12
193
194 static
195 const FT_Frame_Field pcf_metric_header[] =
196 {
197 #undef FT_STRUCTURE
198 #define FT_STRUCTURE PCF_MetricRec
199
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
208 };
209
210
211 static
212 const FT_Frame_Field pcf_metric_msb_header[] =
213 {
214 #undef FT_STRUCTURE
215 #define FT_STRUCTURE PCF_MetricRec
216
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
225 };
226
227
228 #define PCF_COMPRESSED_METRIC_SIZE 5
229
230 static
231 const FT_Frame_Field pcf_compressed_metric_header[] =
232 {
233 #undef FT_STRUCTURE
234 #define FT_STRUCTURE PCF_Compressed_MetricRec
235
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
243 };
244
245
246 static FT_Error
247 pcf_get_metric( FT_Stream stream,
248 FT_ULong format,
249 PCF_Metric metric )
250 {
251 FT_Error error = PCF_Err_Ok;
252
253
254 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
255 {
256 const FT_Frame_Field* fields;
257
258
259 /* parsing normal metrics */
260 fields = PCF_BYTE_ORDER( format ) == MSBFirst
261 ? pcf_metric_msb_header
262 : pcf_metric_header;
263
264 /* the following sets `error' but doesn't return in case of failure */
265 (void)FT_STREAM_READ_FIELDS( fields, metric );
266 }
267 else
268 {
269 PCF_Compressed_MetricRec compr;
270
271
272 /* parsing compressed metrics */
273 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
274 goto Exit;
275
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;
282 }
283
284 Exit:
285 return error;
286 }
287
288
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 )
296 {
297 FT_Error error = PCF_Err_Invalid_File_Format;
298 FT_ULong i;
299
300
301 for ( i = 0; i < ntables; i++ )
302 if ( tables[i].type == type )
303 {
304 if ( stream->pos > tables[i].offset )
305 {
306 error = PCF_Err_Invalid_Stream_Skip;
307 goto Fail;
308 }
309
310 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
311 {
312 error = PCF_Err_Invalid_Stream_Skip;
313 goto Fail;
314 }
315
316 *asize = tables[i].size;
317 *aformat = tables[i].format;
318
319 return PCF_Err_Ok;
320 }
321
322 Fail:
323 *asize = 0;
324 return error;
325 }
326
327
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 )
332 {
333 FT_ULong i;
334
335
336 for ( i = 0; i < ntables; i++ )
337 if ( tables[i].type == type )
338 return TRUE;
339
340 return FALSE;
341 }
342
343
344 #define PCF_PROPERTY_SIZE 9
345
346 static
347 const FT_Frame_Field pcf_property_header[] =
348 {
349 #undef FT_STRUCTURE
350 #define FT_STRUCTURE PCF_ParsePropertyRec
351
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
357 };
358
359
360 static
361 const FT_Frame_Field pcf_property_msb_header[] =
362 {
363 #undef FT_STRUCTURE
364 #define FT_STRUCTURE PCF_ParsePropertyRec
365
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
371 };
372
373
374 FT_LOCAL_DEF( PCF_Property )
375 pcf_find_property( PCF_Face face,
376 const FT_String* prop )
377 {
378 PCF_Property properties = face->properties;
379 FT_Bool found = 0;
380 int i;
381
382
383 for ( i = 0 ; i < face->nprops && !found; i++ )
384 {
385 if ( !ft_strcmp( properties[i].name, prop ) )
386 found = 1;
387 }
388
389 if ( found )
390 return properties + i - 1;
391 else
392 return NULL;
393 }
394
395
396 static FT_Error
397 pcf_get_properties( FT_Stream stream,
398 PCF_Face face )
399 {
400 PCF_ParseProperty props = 0;
401 PCF_Property properties;
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;
408
409
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;
418
419 if ( FT_READ_ULONG_LE( format ) )
420 goto Bail;
421
422 FT_TRACE4(( "pcf_get_properties:\n" ));
423
424 FT_TRACE4(( " format = %ld\n", format ));
425
426 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
427 goto Bail;
428
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;
435
436 FT_TRACE4(( " nprop = %d (truncate %d props)\n",
437 (int)nprops, nprops - (int)nprops ));
438
439 nprops = (int)nprops;
440
441 /* rough estimate */
442 if ( nprops > size / PCF_PROPERTY_SIZE )
443 {
444 error = PCF_Err_Invalid_Table;
445 goto Bail;
446 }
447
448 face->nprops = (int)nprops;
449
450 if ( FT_NEW_ARRAY( props, nprops ) )
451 goto Bail;
452
453 for ( i = 0; i < nprops; i++ )
454 {
455 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
456 {
457 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
458 goto Bail;
459 }
460 else
461 {
462 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
463 goto Bail;
464 }
465 }
466
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 )
473 {
474 i = 4 - ( nprops & 3 );
475 if ( FT_STREAM_SKIP( i ) )
476 {
477 error = PCF_Err_Invalid_Stream_Skip;
478 goto Bail;
479 }
480 }
481
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;
488
489 FT_TRACE4(( " string_size = %ld\n", string_size ));
490
491 /* rough estimate */
492 if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
493 {
494 error = PCF_Err_Invalid_Table;
495 goto Bail;
496 }
497
498 if ( FT_NEW_ARRAY( strings, string_size ) )
499 goto Bail;
500
501 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
502 if ( error )
503 goto Bail;
504
505 if ( FT_NEW_ARRAY( properties, nprops ) )
506 goto Bail;
507
508 face->properties = properties;
509
510 for ( i = 0; i < nprops; i++ )
511 {
512 FT_Long name_offset = props[i].name;
513
514
515 if ( ( name_offset < 0 ) ||
516 ( (FT_ULong)name_offset > string_size ) )
517 {
518 error = PCF_Err_Invalid_Offset;
519 goto Bail;
520 }
521
522 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
523 goto Bail;
524
525 FT_TRACE4(( " %s:", properties[i].name ));
526
527 properties[i].isString = props[i].isString;
528
529 if ( props[i].isString )
530 {
531 FT_Long value_offset = props[i].value;
532
533
534 if ( ( value_offset < 0 ) ||
535 ( (FT_ULong)value_offset > string_size ) )
536 {
537 error = PCF_Err_Invalid_Offset;
538 goto Bail;
539 }
540
541 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
542 goto Bail;
543
544 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
545 }
546 else
547 {
548 properties[i].value.l = props[i].value;
549
550 FT_TRACE4(( " %d\n", properties[i].value.l ));
551 }
552 }
553
554 error = PCF_Err_Ok;
555
556 Bail:
557 FT_FREE( props );
558 FT_FREE( strings );
559
560 return error;
561 }
562
563
564 static FT_Error
565 pcf_get_metrics( FT_Stream stream,
566 PCF_Face face )
567 {
568 FT_Error error = PCF_Err_Ok;
569 FT_Memory memory = FT_FACE(face)->memory;
570 FT_ULong format, size;
571 PCF_Metric metrics = 0;
572 FT_ULong nmetrics, i;
573
574
575 error = pcf_seek_to_table_type( stream,
576 face->toc.tables,
577 face->toc.count,
578 PCF_METRICS,
579 &format,
580 &size );
581 if ( error )
582 return error;
583
584 if ( FT_READ_ULONG_LE( format ) )
585 goto Bail;
586
587 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
588 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
589 return PCF_Err_Invalid_File_Format;
590
591 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
592 {
593 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
594 (void)FT_READ_ULONG( nmetrics );
595 else
596 (void)FT_READ_ULONG_LE( nmetrics );
597 }
598 else
599 {
600 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
601 (void)FT_READ_USHORT( nmetrics );
602 else
603 (void)FT_READ_USHORT_LE( nmetrics );
604 }
605 if ( error )
606 return PCF_Err_Invalid_File_Format;
607
608 face->nmetrics = nmetrics;
609
610 FT_TRACE4(( "pcf_get_metrics:\n" ));
611
612 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
613
614 /* rough estimate */
615 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
616 {
617 if ( nmetrics > size / PCF_METRIC_SIZE )
618 return PCF_Err_Invalid_Table;
619 }
620 else
621 {
622 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
623 return PCF_Err_Invalid_Table;
624 }
625
626 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
627 return PCF_Err_Out_Of_Memory;
628
629 metrics = face->metrics;
630 for ( i = 0; i < nmetrics; i++ )
631 {
632 error = pcf_get_metric( stream, format, metrics + i );
633
634 metrics[i].bits = 0;
635
636 FT_TRACE5(( " idx %d: width=%d, "
637 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
638 i,
639 ( metrics + i )->characterWidth,
640 ( metrics + i )->leftSideBearing,
641 ( metrics + i )->rightSideBearing,
642 ( metrics + i )->ascent,
643 ( metrics + i )->descent,
644 ( metrics + i )->attributes ));
645
646 if ( error )
647 break;
648 }
649
650 if ( error )
651 FT_FREE( face->metrics );
652
653 Bail:
654 return error;
655 }
656
657
658 static FT_Error
659 pcf_get_bitmaps( FT_Stream stream,
660 PCF_Face face )
661 {
662 FT_Error error = PCF_Err_Ok;
663 FT_Memory memory = FT_FACE(face)->memory;
664 FT_Long* offsets;
665 FT_Long bitmapSizes[GLYPHPADOPTIONS];
666 FT_ULong format, size;
667 FT_ULong nbitmaps, i, sizebitmaps = 0;
668
669
670 error = pcf_seek_to_table_type( stream,
671 face->toc.tables,
672 face->toc.count,
673 PCF_BITMAPS,
674 &format,
675 &size );
676 if ( error )
677 return error;
678
679 error = FT_Stream_EnterFrame( stream, 8 );
680 if ( error )
681 return error;
682
683 format = FT_GET_ULONG_LE();
684 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
685 nbitmaps = FT_GET_ULONG();
686 else
687 nbitmaps = FT_GET_ULONG_LE();
688
689 FT_Stream_ExitFrame( stream );
690
691 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
692 return PCF_Err_Invalid_File_Format;
693
694 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
695
696 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
697
698 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
699 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
700 return PCF_Err_Invalid_File_Format;
701
702 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
703 return error;
704
705 for ( i = 0; i < nbitmaps; i++ )
706 {
707 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
708 (void)FT_READ_LONG( offsets[i] );
709 else
710 (void)FT_READ_LONG_LE( offsets[i] );
711
712 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
713 i, offsets[i], offsets[i] ));
714 }
715 if ( error )
716 goto Bail;
717
718 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
719 {
720 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
721 (void)FT_READ_LONG( bitmapSizes[i] );
722 else
723 (void)FT_READ_LONG_LE( bitmapSizes[i] );
724 if ( error )
725 goto Bail;
726
727 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
728
729 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
730 }
731
732 FT_TRACE4(( " %d bitmaps, padding index %ld\n",
733 nbitmaps,
734 PCF_GLYPH_PAD_INDEX( format ) ));
735 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps ));
736
737 FT_UNUSED( sizebitmaps ); /* only used for debugging */
738
739 for ( i = 0; i < nbitmaps; i++ )
740 {
741 /* rough estimate */
742 if ( ( offsets[i] < 0 ) ||
743 ( (FT_ULong)offsets[i] > size ) )
744 {
745 FT_TRACE0(( "pcf_get_bitmaps:"
746 " invalid offset to bitmap data of glyph %d\n", i ));
747 }
748 else
749 face->metrics[i].bits = stream->pos + offsets[i];
750 }
751
752 face->bitmapsFormat = format;
753
754 Bail:
755 FT_FREE( offsets );
756 return error;
757 }
758
759
760 static FT_Error
761 pcf_get_encodings( FT_Stream stream,
762 PCF_Face face )
763 {
764 FT_Error error = PCF_Err_Ok;
765 FT_Memory memory = FT_FACE(face)->memory;
766 FT_ULong format, size;
767 int firstCol, lastCol;
768 int firstRow, lastRow;
769 int nencoding, encodingOffset;
770 int i, j;
771 PCF_Encoding tmpEncoding, encoding = 0;
772
773
774 error = pcf_seek_to_table_type( stream,
775 face->toc.tables,
776 face->toc.count,
777 PCF_BDF_ENCODINGS,
778 &format,
779 &size );
780 if ( error )
781 return error;
782
783 error = FT_Stream_EnterFrame( stream, 14 );
784 if ( error )
785 return error;
786
787 format = FT_GET_ULONG_LE();
788
789 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
790 {
791 firstCol = FT_GET_SHORT();
792 lastCol = FT_GET_SHORT();
793 firstRow = FT_GET_SHORT();
794 lastRow = FT_GET_SHORT();
795 face->defaultChar = FT_GET_SHORT();
796 }
797 else
798 {
799 firstCol = FT_GET_SHORT_LE();
800 lastCol = FT_GET_SHORT_LE();
801 firstRow = FT_GET_SHORT_LE();
802 lastRow = FT_GET_SHORT_LE();
803 face->defaultChar = FT_GET_SHORT_LE();
804 }
805
806 FT_Stream_ExitFrame( stream );
807
808 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
809 return PCF_Err_Invalid_File_Format;
810
811 FT_TRACE4(( "pdf_get_encodings:\n" ));
812
813 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
814 firstCol, lastCol, firstRow, lastRow ));
815
816 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
817
818 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
819 return PCF_Err_Out_Of_Memory;
820
821 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
822 if ( error )
823 goto Bail;
824
825 for ( i = 0, j = 0 ; i < nencoding; i++ )
826 {
827 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
828 encodingOffset = FT_GET_SHORT();
829 else
830 encodingOffset = FT_GET_SHORT_LE();
831
832 if ( encodingOffset != -1 )
833 {
834 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
835 firstRow ) * 256 ) +
836 ( ( i % ( lastCol - firstCol + 1 ) ) +
837 firstCol );
838
839 tmpEncoding[j].glyph = (FT_Short)encodingOffset;
840
841 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
842 tmpEncoding[j].enc, tmpEncoding[j].enc,
843 tmpEncoding[j].glyph ));
844
845 j++;
846 }
847 }
848 FT_Stream_ExitFrame( stream );
849
850 if ( FT_NEW_ARRAY( encoding, j ) )
851 goto Bail;
852
853 for ( i = 0; i < j; i++ )
854 {
855 encoding[i].enc = tmpEncoding[i].enc;
856 encoding[i].glyph = tmpEncoding[i].glyph;
857 }
858
859 face->nencodings = j;
860 face->encodings = encoding;
861 FT_FREE( tmpEncoding );
862
863 return error;
864
865 Bail:
866 FT_FREE( encoding );
867 FT_FREE( tmpEncoding );
868 return error;
869 }
870
871
872 static
873 const FT_Frame_Field pcf_accel_header[] =
874 {
875 #undef FT_STRUCTURE
876 #define FT_STRUCTURE PCF_AccelRec
877
878 FT_FRAME_START( 20 ),
879 FT_FRAME_BYTE ( noOverlap ),
880 FT_FRAME_BYTE ( constantMetrics ),
881 FT_FRAME_BYTE ( terminalFont ),
882 FT_FRAME_BYTE ( constantWidth ),
883 FT_FRAME_BYTE ( inkInside ),
884 FT_FRAME_BYTE ( inkMetrics ),
885 FT_FRAME_BYTE ( drawDirection ),
886 FT_FRAME_SKIP_BYTES( 1 ),
887 FT_FRAME_LONG_LE ( fontAscent ),
888 FT_FRAME_LONG_LE ( fontDescent ),
889 FT_FRAME_LONG_LE ( maxOverlap ),
890 FT_FRAME_END
891 };
892
893
894 static
895 const FT_Frame_Field pcf_accel_msb_header[] =
896 {
897 #undef FT_STRUCTURE
898 #define FT_STRUCTURE PCF_AccelRec
899
900 FT_FRAME_START( 20 ),
901 FT_FRAME_BYTE ( noOverlap ),
902 FT_FRAME_BYTE ( constantMetrics ),
903 FT_FRAME_BYTE ( terminalFont ),
904 FT_FRAME_BYTE ( constantWidth ),
905 FT_FRAME_BYTE ( inkInside ),
906 FT_FRAME_BYTE ( inkMetrics ),
907 FT_FRAME_BYTE ( drawDirection ),
908 FT_FRAME_SKIP_BYTES( 1 ),
909 FT_FRAME_LONG ( fontAscent ),
910 FT_FRAME_LONG ( fontDescent ),
911 FT_FRAME_LONG ( maxOverlap ),
912 FT_FRAME_END
913 };
914
915
916 static FT_Error
917 pcf_get_accel( FT_Stream stream,
918 PCF_Face face,
919 FT_ULong type )
920 {
921 FT_ULong format, size;
922 FT_Error error = PCF_Err_Ok;
923 PCF_Accel accel = &face->accel;
924
925
926 error = pcf_seek_to_table_type( stream,
927 face->toc.tables,
928 face->toc.count,
929 type,
930 &format,
931 &size );
932 if ( error )
933 goto Bail;
934
935 if ( FT_READ_ULONG_LE( format ) )
936 goto Bail;
937
938 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
939 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
940 goto Bail;
941
942 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
943 {
944 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
945 goto Bail;
946 }
947 else
948 {
949 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
950 goto Bail;
951 }
952
953 error = pcf_get_metric( stream,
954 format & ( ~PCF_FORMAT_MASK ),
955 &(accel->minbounds) );
956 if ( error )
957 goto Bail;
958
959 error = pcf_get_metric( stream,
960 format & ( ~PCF_FORMAT_MASK ),
961 &(accel->maxbounds) );
962 if ( error )
963 goto Bail;
964
965 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
966 {
967 error = pcf_get_metric( stream,
968 format & ( ~PCF_FORMAT_MASK ),
969 &(accel->ink_minbounds) );
970 if ( error )
971 goto Bail;
972
973 error = pcf_get_metric( stream,
974 format & ( ~PCF_FORMAT_MASK ),
975 &(accel->ink_maxbounds) );
976 if ( error )
977 goto Bail;
978 }
979 else
980 {
981 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
982 accel->ink_maxbounds = accel->maxbounds;
983 }
984
985 Bail:
986 return error;
987 }
988
989
990 static FT_Error
991 pcf_interpret_style( PCF_Face pcf )
992 {
993 FT_Error error = PCF_Err_Ok;
994 FT_Face face = FT_FACE( pcf );
995 FT_Memory memory = face->memory;
996
997 PCF_Property prop;
998
999 size_t nn, len;
1000 char* strings[4] = { NULL, NULL, NULL, NULL };
1001 size_t lengths[4];
1002
1003
1004 face->style_flags = 0;
1005
1006 prop = pcf_find_property( pcf, "SLANT" );
1007 if ( prop && prop->isString &&
1008 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1009 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1010 {
1011 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1012 strings[2] = ( *(prop->value.atom) == 'O' ||
1013 *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1014 : (char *)"Italic";
1015 }
1016
1017 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1018 if ( prop && prop->isString &&
1019 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1020 {
1021 face->style_flags |= FT_STYLE_FLAG_BOLD;
1022 strings[1] = (char *)"Bold";
1023 }
1024
1025 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1026 if ( prop && prop->isString &&
1027 *(prop->value.atom) &&
1028 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1029 strings[3] = (char *)(prop->value.atom);
1030
1031 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1032 if ( prop && prop->isString &&
1033 *(prop->value.atom) &&
1034 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1035 strings[0] = (char *)(prop->value.atom);
1036
1037 for ( len = 0, nn = 0; nn < 4; nn++ )
1038 {
1039 lengths[nn] = 0;
1040 if ( strings[nn] )
1041 {
1042 lengths[nn] = ft_strlen( strings[nn] );
1043 len += lengths[nn] + 1;
1044 }
1045 }
1046
1047 if ( len == 0 )
1048 {
1049 strings[0] = (char *)"Regular";
1050 lengths[0] = ft_strlen( strings[0] );
1051 len = lengths[0] + 1;
1052 }
1053
1054 {
1055 char* s;
1056
1057
1058 if ( FT_ALLOC( face->style_name, len ) )
1059 return error;
1060
1061 s = face->style_name;
1062
1063 for ( nn = 0; nn < 4; nn++ )
1064 {
1065 char* src = strings[nn];
1066
1067
1068 len = lengths[nn];
1069
1070 if ( src == NULL )
1071 continue;
1072
1073 /* separate elements with a space */
1074 if ( s != face->style_name )
1075 *s++ = ' ';
1076
1077 ft_memcpy( s, src, len );
1078
1079 /* need to convert spaces to dashes for */
1080 /* add_style_name and setwidth_name */
1081 if ( nn == 0 || nn == 3 )
1082 {
1083 size_t mm;
1084
1085
1086 for ( mm = 0; mm < len; mm++ )
1087 if (s[mm] == ' ')
1088 s[mm] = '-';
1089 }
1090
1091 s += len;
1092 }
1093 *s = 0;
1094 }
1095
1096 return error;
1097 }
1098
1099
1100 FT_LOCAL_DEF( FT_Error )
1101 pcf_load_font( FT_Stream stream,
1102 PCF_Face face )
1103 {
1104 FT_Error error = PCF_Err_Ok;
1105 FT_Memory memory = FT_FACE(face)->memory;
1106 FT_Bool hasBDFAccelerators;
1107
1108
1109 error = pcf_read_TOC( stream, face );
1110 if ( error )
1111 goto Exit;
1112
1113 error = pcf_get_properties( stream, face );
1114 if ( error )
1115 goto Exit;
1116
1117 /* Use the old accelerators if no BDF accelerators are in the file. */
1118 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1119 face->toc.count,
1120 PCF_BDF_ACCELERATORS );
1121 if ( !hasBDFAccelerators )
1122 {
1123 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1124 if ( error )
1125 goto Exit;
1126 }
1127
1128 /* metrics */
1129 error = pcf_get_metrics( stream, face );
1130 if ( error )
1131 goto Exit;
1132
1133 /* bitmaps */
1134 error = pcf_get_bitmaps( stream, face );
1135 if ( error )
1136 goto Exit;
1137
1138 /* encodings */
1139 error = pcf_get_encodings( stream, face );
1140 if ( error )
1141 goto Exit;
1142
1143 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1144 if ( hasBDFAccelerators )
1145 {
1146 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1147 if ( error )
1148 goto Exit;
1149 }
1150
1151 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1152
1153 /* now construct the face object */
1154 {
1155 FT_Face root = FT_FACE( face );
1156 PCF_Property prop;
1157
1158
1159 root->num_faces = 1;
1160 root->face_index = 0;
1161 root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1162 FT_FACE_FLAG_HORIZONTAL |
1163 FT_FACE_FLAG_FAST_GLYPHS;
1164
1165 if ( face->accel.constantWidth )
1166 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1167
1168 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1169 goto Exit;
1170
1171 prop = pcf_find_property( face, "FAMILY_NAME" );
1172 if ( prop && prop->isString )
1173 {
1174 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1175 goto Exit;
1176 }
1177 else
1178 root->family_name = NULL;
1179
1180 /*
1181 * Note: We shift all glyph indices by +1 since we must
1182 * respect the convention that glyph 0 always corresponds
1183 * to the `missing glyph'.
1184 *
1185 * This implies bumping the number of `available' glyphs by 1.
1186 */
1187 root->num_glyphs = face->nmetrics + 1;
1188
1189 root->num_fixed_sizes = 1;
1190 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1191 goto Exit;
1192
1193 {
1194 FT_Bitmap_Size* bsize = root->available_sizes;
1195 FT_Short resolution_x = 0, resolution_y = 0;
1196
1197
1198 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1199
1200 #if 0
1201 bsize->height = face->accel.maxbounds.ascent << 6;
1202 #endif
1203 bsize->height = (FT_Short)( face->accel.fontAscent +
1204 face->accel.fontDescent );
1205
1206 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1207 if ( prop )
1208 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1209 else
1210 bsize->width = (FT_Short)( bsize->height * 2/3 );
1211
1212 prop = pcf_find_property( face, "POINT_SIZE" );
1213 if ( prop )
1214 /* convert from 722.7 decipoints to 72 points per inch */
1215 bsize->size =
1216 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1217
1218 prop = pcf_find_property( face, "PIXEL_SIZE" );
1219 if ( prop )
1220 bsize->y_ppem = (FT_Short)prop->value.l << 6;
1221
1222 prop = pcf_find_property( face, "RESOLUTION_X" );
1223 if ( prop )
1224 resolution_x = (FT_Short)prop->value.l;
1225
1226 prop = pcf_find_property( face, "RESOLUTION_Y" );
1227 if ( prop )
1228 resolution_y = (FT_Short)prop->value.l;
1229
1230 if ( bsize->y_ppem == 0 )
1231 {
1232 bsize->y_ppem = bsize->size;
1233 if ( resolution_y )
1234 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1235 }
1236 if ( resolution_x && resolution_y )
1237 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1238 else
1239 bsize->x_ppem = bsize->y_ppem;
1240 }
1241
1242 /* set up charset */
1243 {
1244 PCF_Property charset_registry = 0, charset_encoding = 0;
1245
1246
1247 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1248 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1249
1250 if ( charset_registry && charset_registry->isString &&
1251 charset_encoding && charset_encoding->isString )
1252 {
1253 if ( FT_STRDUP( face->charset_encoding,
1254 charset_encoding->value.atom ) ||
1255 FT_STRDUP( face->charset_registry,
1256 charset_registry->value.atom ) )
1257 goto Exit;
1258 }
1259 }
1260 }
1261
1262 Exit:
1263 if ( error )
1264 {
1265 /* This is done to respect the behaviour of the original */
1266 /* PCF font driver. */
1267 error = PCF_Err_Invalid_File_Format;
1268 }
1269
1270 return error;
1271 }
1272
1273
1274 /* END */