1/* pcfread.c
2
3 FreeType font driver for pcf fonts
4
5 Copyright 2000-2010, 2012-2014 by
6 Francesco Zappa Nardelli
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24THE SOFTWARE.
25*/
26
27
28
29#include <freetype/internal/ftdebug.h>
30#include <freetype/internal/ftstream.h>
31#include <freetype/internal/ftobjs.h>
32
33#include "pcf.h"
34#include "pcfread.h"
35
36#include "pcferror.h"
37
38
39 /**************************************************************************
40 *
41 * The macro FT_COMPONENT is used in trace mode. It is an implicit
42 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
43 * messages during execution.
44 */
45#undef FT_COMPONENT
46#define FT_COMPONENT pcfread
47
48
49#ifdef FT_DEBUG_LEVEL_TRACE
50 static const char* const tableNames[] =
51 {
52 "properties",
53 "accelerators",
54 "metrics",
55 "bitmaps",
56 "ink metrics",
57 "encodings",
58 "swidths",
59 "glyph names",
60 "BDF accelerators"
61 };
62#endif
63
64
65 static
66 const FT_Frame_Field pcf_toc_header[] =
67 {
68#undef FT_STRUCTURE
69#define FT_STRUCTURE PCF_TocRec
70
71 FT_FRAME_START( 8 ),
72 FT_FRAME_ULONG_LE( version ),
73 FT_FRAME_ULONG_LE( count ),
74 FT_FRAME_END
75 };
76
77
78 static
79 const FT_Frame_Field pcf_table_header[] =
80 {
81#undef FT_STRUCTURE
82#define FT_STRUCTURE PCF_TableRec
83
84 FT_FRAME_START( 16 ),
85 FT_FRAME_ULONG_LE( type ),
86 FT_FRAME_ULONG_LE( format ),
87 FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */
88 FT_FRAME_ULONG_LE( offset ),
89 FT_FRAME_END
90 };
91
92
93 static FT_Error
94 pcf_read_TOC( FT_Stream stream,
95 PCF_Face face )
96 {
97 FT_Error error;
98 PCF_Toc toc = &face->toc;
99 PCF_Table tables;
100
101 FT_Memory memory = FT_FACE( face )->memory;
102 FT_UInt n;
103
104 FT_ULong size;
105
106
107 if ( FT_STREAM_SEEK( 0 ) ||
108 FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) )
109 return FT_THROW( Cannot_Open_Resource );
110
111 if ( toc->version != PCF_FILE_VERSION ||
112 toc->count == 0 )
113 return FT_THROW( Invalid_File_Format );
114
115 if ( stream->size < 16 )
116 return FT_THROW( Invalid_File_Format );
117
118 /* we need 16 bytes per TOC entry, */
119 /* and there can be most 9 tables */
120 if ( toc->count > ( stream->size >> 4 ) ||
121 toc->count > 9 )
122 {
123 FT_TRACE0(( "pcf_read_TOC: adjusting number of tables"
124 " (from %ld to %ld)\n",
125 toc->count,
126 FT_MIN( stream->size >> 4, 9 ) ));
127 toc->count = FT_MIN( stream->size >> 4, 9 );
128 }
129
130 if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) )
131 return error;
132
133 tables = face->toc.tables;
134 for ( n = 0; n < toc->count; n++ )
135 {
136 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
137 goto Exit;
138 tables++;
139 }
140
141 /* Sort tables and check for overlaps. Because they are almost */
142 /* always ordered already, an in-place bubble sort with simultaneous */
143 /* boundary checking seems appropriate. */
144 tables = face->toc.tables;
145
146 for ( n = 0; n < toc->count - 1; n++ )
147 {
148 FT_UInt i, have_change;
149
150
151 have_change = 0;
152
153 for ( i = 0; i < toc->count - 1 - n; i++ )
154 {
155 PCF_TableRec tmp;
156
157
158 if ( tables[i].offset > tables[i + 1].offset )
159 {
160 tmp = tables[i];
161 tables[i] = tables[i + 1];
162 tables[i + 1] = tmp;
163
164 have_change = 1;
165 }
166
167 if ( ( tables[i].size > tables[i + 1].offset ) ||
168 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
169 {
170 error = FT_THROW( Invalid_Offset );
171 goto Exit;
172 }
173 }
174
175 if ( !have_change )
176 break;
177 }
178
179 /*
180 * We now check whether the `size' and `offset' values are reasonable:
181 * `offset' + `size' must not exceed the stream size.
182 *
183 * Note, however, that X11's `pcfWriteFont' routine (used by the
184 * `bdftopcf' program to create PCF font files) has two special
185 * features.
186 *
187 * - It always assigns the accelerator table a size of 100 bytes in the
188 * TOC, regardless of its real size, which can vary between 34 and 72
189 * bytes.
190 *
191 * - Due to the way the routine is designed, it ships out the last font
192 * table with its real size, ignoring the TOC's size value. Since
193 * the TOC size values are always rounded up to a multiple of 4, the
194 * difference can be up to three bytes for all tables except the
195 * accelerator table, for which the difference can be as large as 66
196 * bytes.
197 *
198 */
199
200 tables = face->toc.tables;
201 size = stream->size;
202
203 for ( n = 0; n < toc->count - 1; n++ )
204 {
205 /* we need two checks to avoid overflow */
206 if ( ( tables->size > size ) ||
207 ( tables->offset > size - tables->size ) )
208 {
209 error = FT_THROW( Invalid_Table );
210 goto Exit;
211 }
212 tables++;
213 }
214
215 /* only check `tables->offset' for last table element ... */
216 if ( ( tables->offset > size ) )
217 {
218 error = FT_THROW( Invalid_Table );
219 goto Exit;
220 }
221 /* ... and adjust `tables->size' to the real value if necessary */
222 if ( tables->size > size - tables->offset )
223 tables->size = size - tables->offset;
224
225#ifdef FT_DEBUG_LEVEL_TRACE
226
227 {
228 FT_UInt i, j;
229 const char* name = "?";
230
231
232 FT_TRACE4(( "pcf_read_TOC:\n" ));
233
234 FT_TRACE4(( " number of tables: %ld\n", face->toc.count ));
235
236 tables = face->toc.tables;
237 for ( i = 0; i < toc->count; i++ )
238 {
239 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
240 j++ )
241 if ( tables[i].type == 1UL << j )
242 name = tableNames[j];
243
244 FT_TRACE4(( " %d: type=%s, format=0x%lX,"
245 " size=%ld (0x%lX), offset=%ld (0x%lX)\n",
246 i, name,
247 tables[i].format,
248 tables[i].size, tables[i].size,
249 tables[i].offset, tables[i].offset ));
250 }
251 }
252
253#endif
254
255 return FT_Err_Ok;
256
257 Exit:
258 FT_FREE( face->toc.tables );
259 return error;
260 }
261
262
263#define PCF_METRIC_SIZE 12
264
265 static
266 const FT_Frame_Field pcf_metric_header[] =
267 {
268#undef FT_STRUCTURE
269#define FT_STRUCTURE PCF_MetricRec
270
271 FT_FRAME_START( PCF_METRIC_SIZE ),
272 FT_FRAME_SHORT_LE( leftSideBearing ),
273 FT_FRAME_SHORT_LE( rightSideBearing ),
274 FT_FRAME_SHORT_LE( characterWidth ),
275 FT_FRAME_SHORT_LE( ascent ),
276 FT_FRAME_SHORT_LE( descent ),
277 FT_FRAME_SHORT_LE( attributes ),
278 FT_FRAME_END
279 };
280
281
282 static
283 const FT_Frame_Field pcf_metric_msb_header[] =
284 {
285#undef FT_STRUCTURE
286#define FT_STRUCTURE PCF_MetricRec
287
288 FT_FRAME_START( PCF_METRIC_SIZE ),
289 FT_FRAME_SHORT( leftSideBearing ),
290 FT_FRAME_SHORT( rightSideBearing ),
291 FT_FRAME_SHORT( characterWidth ),
292 FT_FRAME_SHORT( ascent ),
293 FT_FRAME_SHORT( descent ),
294 FT_FRAME_SHORT( attributes ),
295 FT_FRAME_END
296 };
297
298
299#define PCF_COMPRESSED_METRIC_SIZE 5
300
301 static
302 const FT_Frame_Field pcf_compressed_metric_header[] =
303 {
304#undef FT_STRUCTURE
305#define FT_STRUCTURE PCF_Compressed_MetricRec
306
307 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
308 FT_FRAME_BYTE( leftSideBearing ),
309 FT_FRAME_BYTE( rightSideBearing ),
310 FT_FRAME_BYTE( characterWidth ),
311 FT_FRAME_BYTE( ascent ),
312 FT_FRAME_BYTE( descent ),
313 FT_FRAME_END
314 };
315
316
317 static FT_Error
318 pcf_get_metric( FT_Stream stream,
319 FT_ULong format,
320 PCF_Metric metric )
321 {
322 FT_Error error = FT_Err_Ok;
323
324
325 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
326 {
327 const FT_Frame_Field* fields;
328
329
330 /* parsing normal metrics */
331 fields = ( PCF_BYTE_ORDER( format ) == MSBFirst )
332 ? pcf_metric_msb_header
333 : pcf_metric_header;
334
335 /* the following sets `error' but doesn't return in case of failure */
336 (void)FT_STREAM_READ_FIELDS( fields, metric );
337 }
338 else
339 {
340 PCF_Compressed_MetricRec compr;
341
342
343 /* parsing compressed metrics */
344 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
345 goto Exit;
346
347 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
348 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
349 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
350 metric->ascent = (FT_Short)( compr.ascent - 0x80 );
351 metric->descent = (FT_Short)( compr.descent - 0x80 );
352 metric->attributes = 0;
353 }
354
355 FT_TRACE5(( " width=%d,"
356 " lsb=%d, rsb=%d,"
357 " ascent=%d, descent=%d,"
358 " attributes=%d\n",
359 metric->characterWidth,
360 metric->leftSideBearing,
361 metric->rightSideBearing,
362 metric->ascent,
363 metric->descent,
364 metric->attributes ));
365
366 Exit:
367 return error;
368 }
369
370
371 static FT_Error
372 pcf_seek_to_table_type( FT_Stream stream,
373 PCF_Table tables,
374 FT_ULong ntables, /* same as PCF_Toc->count */
375 FT_ULong type,
376 FT_ULong *aformat,
377 FT_ULong *asize )
378 {
379 FT_Error error = FT_ERR( Invalid_File_Format );
380 FT_ULong i;
381
382
383 for ( i = 0; i < ntables; i++ )
384 if ( tables[i].type == type )
385 {
386 if ( stream->pos > tables[i].offset )
387 {
388 error = FT_THROW( Invalid_Stream_Skip );
389 goto Fail;
390 }
391
392 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
393 {
394 error = FT_THROW( Invalid_Stream_Skip );
395 goto Fail;
396 }
397
398 *asize = tables[i].size;
399 *aformat = tables[i].format;
400
401 return FT_Err_Ok;
402 }
403
404 Fail:
405 *asize = 0;
406 return error;
407 }
408
409
410 static FT_Bool
411 pcf_has_table_type( PCF_Table tables,
412 FT_ULong ntables, /* same as PCF_Toc->count */
413 FT_ULong type )
414 {
415 FT_ULong i;
416
417
418 for ( i = 0; i < ntables; i++ )
419 if ( tables[i].type == type )
420 return TRUE;
421
422 return FALSE;
423 }
424
425
426#define PCF_PROPERTY_SIZE 9
427
428 static
429 const FT_Frame_Field pcf_property_header[] =
430 {
431#undef FT_STRUCTURE
432#define FT_STRUCTURE PCF_ParsePropertyRec
433
434 FT_FRAME_START( PCF_PROPERTY_SIZE ),
435 FT_FRAME_LONG_LE( name ),
436 FT_FRAME_BYTE ( isString ),
437 FT_FRAME_LONG_LE( value ),
438 FT_FRAME_END
439 };
440
441
442 static
443 const FT_Frame_Field pcf_property_msb_header[] =
444 {
445#undef FT_STRUCTURE
446#define FT_STRUCTURE PCF_ParsePropertyRec
447
448 FT_FRAME_START( PCF_PROPERTY_SIZE ),
449 FT_FRAME_LONG( name ),
450 FT_FRAME_BYTE( isString ),
451 FT_FRAME_LONG( value ),
452 FT_FRAME_END
453 };
454
455
456 FT_LOCAL_DEF( PCF_Property )
457 pcf_find_property( PCF_Face face,
458 const FT_String* prop )
459 {
460 PCF_Property properties = face->properties;
461 FT_Bool found = 0;
462 int i;
463
464
465 for ( i = 0; i < face->nprops && !found; i++ )
466 {
467 if ( !ft_strcmp( properties[i].name, prop ) )
468 found = 1;
469 }
470
471 if ( found )
472 return properties + i - 1;
473 else
474 return NULL;
475 }
476
477
478 static FT_Error
479 pcf_get_properties( FT_Stream stream,
480 PCF_Face face )
481 {
482 PCF_ParseProperty props = NULL;
483 PCF_Property properties = NULL;
484 FT_ULong nprops, orig_nprops, i;
485 FT_ULong format, size;
486 FT_Error error;
487 FT_Memory memory = FT_FACE( face )->memory;
488 FT_ULong string_size;
489 FT_String* strings = NULL;
490
491
492 error = pcf_seek_to_table_type( stream,
493 face->toc.tables,
494 face->toc.count,
495 PCF_PROPERTIES,
496 &format,
497 &size );
498 if ( error )
499 goto Bail;
500
501 if ( FT_READ_ULONG_LE( format ) )
502 goto Bail;
503
504 FT_TRACE4(( "pcf_get_properties:\n" ));
505 FT_TRACE4(( " format: 0x%lX (%s)\n",
506 format,
507 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
508
509 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
510 goto Bail;
511
512 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
513 (void)FT_READ_ULONG( orig_nprops );
514 else
515 (void)FT_READ_ULONG_LE( orig_nprops );
516 if ( error )
517 goto Bail;
518
519 FT_TRACE4(( " number of properties: %ld\n", orig_nprops ));
520
521 /* rough estimate */
522 if ( orig_nprops > size / PCF_PROPERTY_SIZE )
523 {
524 error = FT_THROW( Invalid_Table );
525 goto Bail;
526 }
527
528 /* as a heuristic limit to avoid excessive allocation in */
529 /* gzip bombs (i.e., very small, invalid input data that */
530 /* pretends to expand to an insanely large file) we only */
531 /* load the first 256 properties */
532 if ( orig_nprops > 256 )
533 {
534 FT_TRACE0(( "pcf_get_properties:"
535 " only loading first 256 properties\n" ));
536 nprops = 256;
537 }
538 else
539 nprops = orig_nprops;
540
541 face->nprops = (int)nprops;
542
543 if ( FT_QNEW_ARRAY( props, nprops ) )
544 goto Bail;
545
546 for ( i = 0; i < nprops; i++ )
547 {
548 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
549 {
550 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
551 goto Bail;
552 }
553 else
554 {
555 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
556 goto Bail;
557 }
558 }
559
560 /* this skip will only work if we really have an extremely large */
561 /* number of properties; it will fail for fake data, avoiding an */
562 /* unnecessarily large allocation later on */
563 if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) )
564 {
565 error = FT_THROW( Invalid_Stream_Skip );
566 goto Bail;
567 }
568
569 /* pad the property array */
570 /* */
571 /* clever here - nprops is the same as the number of odd-units read, */
572 /* as only isStringProp are odd length (Keith Packard) */
573 /* */
574 if ( orig_nprops & 3 )
575 {
576 i = 4 - ( orig_nprops & 3 );
577 if ( FT_STREAM_SKIP( i ) )
578 {
579 error = FT_THROW( Invalid_Stream_Skip );
580 goto Bail;
581 }
582 }
583
584 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
585 (void)FT_READ_ULONG( string_size );
586 else
587 (void)FT_READ_ULONG_LE( string_size );
588 if ( error )
589 goto Bail;
590
591 FT_TRACE4(( " string size: %ld\n", string_size ));
592
593 /* rough estimate */
594 if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE )
595 {
596 error = FT_THROW( Invalid_Table );
597 goto Bail;
598 }
599
600 /* the strings in the `strings' array are PostScript strings, */
601 /* which can have a maximum length of 65536 characters each */
602 if ( string_size > 16777472 ) /* 256 * (65536 + 1) */
603 {
604 FT_TRACE0(( "pcf_get_properties:"
605 " loading only 16777472 bytes of strings array\n" ));
606 string_size = 16777472;
607 }
608
609 /* allocate one more byte so that we have a final null byte */
610 if ( FT_QALLOC( strings, string_size + 1 ) ||
611 FT_STREAM_READ( strings, string_size ) )
612 goto Bail;
613
614 strings[string_size] = '\0';
615
616 /* zero out in case of failure */
617 if ( FT_NEW_ARRAY( properties, nprops ) )
618 goto Bail;
619
620 face->properties = properties;
621
622 FT_TRACE4(( "\n" ));
623 for ( i = 0; i < nprops; i++ )
624 {
625 FT_Long name_offset = props[i].name;
626
627
628 if ( ( name_offset < 0 ) ||
629 ( (FT_ULong)name_offset > string_size ) )
630 {
631 error = FT_THROW( Invalid_Offset );
632 goto Bail;
633 }
634
635 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
636 goto Bail;
637
638 FT_TRACE4(( " %s:", properties[i].name ));
639
640 properties[i].isString = props[i].isString;
641
642 if ( props[i].isString )
643 {
644 FT_Long value_offset = props[i].value;
645
646
647 if ( ( value_offset < 0 ) ||
648 ( (FT_ULong)value_offset > string_size ) )
649 {
650 error = FT_THROW( Invalid_Offset );
651 goto Bail;
652 }
653
654 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
655 goto Bail;
656
657 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
658 }
659 else
660 {
661 properties[i].value.l = props[i].value;
662
663 FT_TRACE4(( " %ld\n", properties[i].value.l ));
664 }
665 }
666
667 error = FT_Err_Ok;
668
669 Bail:
670 FT_FREE( props );
671 FT_FREE( strings );
672
673 return error;
674 }
675
676
677 static FT_Error
678 pcf_get_metrics( FT_Stream stream,
679 PCF_Face face )
680 {
681 FT_Error error;
682 FT_Memory memory = FT_FACE( face )->memory;
683 FT_ULong format, size;
684 PCF_Metric metrics = NULL;
685 FT_ULong nmetrics, orig_nmetrics, i;
686
687
688 error = pcf_seek_to_table_type( stream,
689 face->toc.tables,
690 face->toc.count,
691 PCF_METRICS,
692 &format,
693 &size );
694 if ( error )
695 return error;
696
697 if ( FT_READ_ULONG_LE( format ) )
698 goto Bail;
699
700 FT_TRACE4(( "pcf_get_metrics:\n" ));
701 FT_TRACE4(( " format: 0x%lX (%s, %s)\n",
702 format,
703 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
704 PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ?
705 "compressed" : "uncompressed" ));
706
707 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
708 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
709 return FT_THROW( Invalid_File_Format );
710
711 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
712 {
713 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
714 (void)FT_READ_ULONG( orig_nmetrics );
715 else
716 (void)FT_READ_ULONG_LE( orig_nmetrics );
717 }
718 else
719 {
720 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
721 (void)FT_READ_USHORT( orig_nmetrics );
722 else
723 (void)FT_READ_USHORT_LE( orig_nmetrics );
724 }
725 if ( error )
726 return FT_THROW( Invalid_File_Format );
727
728 FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics ));
729
730 /* rough estimate */
731 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
732 {
733 if ( orig_nmetrics > size / PCF_METRIC_SIZE )
734 return FT_THROW( Invalid_Table );
735 }
736 else
737 {
738 if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
739 return FT_THROW( Invalid_Table );
740 }
741
742 if ( !orig_nmetrics )
743 return FT_THROW( Invalid_Table );
744
745 /*
746 * PCF is a format from ancient times; Unicode was in its infancy, and
747 * widely used two-byte character sets for CJK scripts (Big 5, GB 2312,
748 * JIS X 0208, etc.) did have at most 15000 characters. Even the more
749 * exotic CNS 11643 and CCCII standards, which were essentially
750 * three-byte character sets, provided less then 65536 assigned
751 * characters.
752 *
753 * While technically possible to have a larger number of glyphs in PCF
754 * files, we thus limit the number to 65535, taking into account that we
755 * synthesize the metrics of glyph 0 to be a copy of the `default
756 * character', and that 0xFFFF in the encodings array indicates a
757 * missing glyph.
758 */
759 if ( orig_nmetrics > 65534 )
760 {
761 FT_TRACE0(( "pcf_get_metrics:"
762 " only loading first 65534 metrics\n" ));
763 nmetrics = 65534;
764 }
765 else
766 nmetrics = orig_nmetrics;
767
768 face->nmetrics = nmetrics + 1;
769
770 if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) )
771 return error;
772
773 /* we handle glyph index 0 later on */
774 metrics = face->metrics + 1;
775
776 FT_TRACE4(( "\n" ));
777 for ( i = 1; i < face->nmetrics; i++, metrics++ )
778 {
779 FT_TRACE5(( " idx %ld:", i ));
780 error = pcf_get_metric( stream, format, metrics );
781
782 metrics->bits = 0;
783
784 if ( error )
785 break;
786
787 /* sanity checks -- those values are used in `PCF_Glyph_Load' to */
788 /* compute a glyph's bitmap dimensions, thus setting them to zero in */
789 /* case of an error disables this particular glyph only */
790 if ( metrics->rightSideBearing < metrics->leftSideBearing ||
791 metrics->ascent < -metrics->descent )
792 {
793 metrics->characterWidth = 0;
794 metrics->leftSideBearing = 0;
795 metrics->rightSideBearing = 0;
796 metrics->ascent = 0;
797 metrics->descent = 0;
798
799 FT_TRACE0(( "pcf_get_metrics:"
800 " invalid metrics for glyph %ld\n", i ));
801 }
802 }
803
804 if ( error )
805 FT_FREE( face->metrics );
806
807 Bail:
808 return error;
809 }
810
811
812 static FT_Error
813 pcf_get_bitmaps( FT_Stream stream,
814 PCF_Face face )
815 {
816 FT_Error error;
817 FT_ULong bitmapSizes[GLYPHPADOPTIONS];
818 FT_ULong format, size, pos;
819 FT_ULong nbitmaps, orig_nbitmaps, i, sizebitmaps = 0;
820
821
822 error = pcf_seek_to_table_type( stream,
823 face->toc.tables,
824 face->toc.count,
825 PCF_BITMAPS,
826 &format,
827 &size );
828 if ( error )
829 return error;
830
831 error = FT_Stream_EnterFrame( stream, 8 );
832 if ( error )
833 return error;
834
835 format = FT_GET_ULONG_LE();
836 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
837 orig_nbitmaps = FT_GET_ULONG();
838 else
839 orig_nbitmaps = FT_GET_ULONG_LE();
840
841 FT_Stream_ExitFrame( stream );
842
843 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
844 FT_TRACE4(( " format: 0x%lX\n", format ));
845 FT_TRACE4(( " (%s, %s,\n",
846 PCF_BYTE_ORDER( format ) == MSBFirst
847 ? "most significant byte first"
848 : "least significant byte first",
849 PCF_BIT_ORDER( format ) == MSBFirst
850 ? "most significant bit first"
851 : "least significant bit first" ));
852 FT_TRACE4(( " padding=%d bit%s, scanning=%d bit%s)\n",
853 8 << PCF_GLYPH_PAD_INDEX( format ),
854 ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s",
855 8 << PCF_SCAN_UNIT_INDEX( format ),
856 ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" ));
857
858 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
859 return FT_THROW( Invalid_File_Format );
860
861 FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps ));
862
863 /* see comment in `pcf_get_metrics' */
864 if ( orig_nbitmaps > 65534 )
865 {
866 FT_TRACE0(( "pcf_get_bitmaps:"
867 " only loading first 65534 bitmaps\n" ));
868 nbitmaps = 65534;
869 }
870 else
871 nbitmaps = orig_nbitmaps;
872
873 /* no extra bitmap for glyph 0 */
874 if ( nbitmaps != face->nmetrics - 1 )
875 return FT_THROW( Invalid_File_Format );
876
877 /* start position of bitmap data */
878 pos = stream->pos + nbitmaps * 4 + 4 * 4;
879
880 FT_TRACE5(( "\n" ));
881 for ( i = 1; i <= nbitmaps; i++ )
882 {
883 FT_ULong offset;
884
885
886 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
887 (void)FT_READ_ULONG( offset );
888 else
889 (void)FT_READ_ULONG_LE( offset );
890
891 FT_TRACE5(( " bitmap %lu: offset %lu (0x%lX)\n",
892 i, offset, offset ));
893
894 /* right now, we only check the offset with a rough estimate; */
895 /* actual bitmaps are only loaded on demand */
896 if ( offset > size )
897 {
898 FT_TRACE0(( "pcf_get_bitmaps:"
899 " invalid offset to bitmap data of glyph %lu\n", i ));
900 face->metrics[i].bits = pos;
901 }
902 else
903 face->metrics[i].bits = pos + offset;
904 }
905 if ( error )
906 goto Bail;
907
908 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
909 {
910 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
911 (void)FT_READ_ULONG( bitmapSizes[i] );
912 else
913 (void)FT_READ_ULONG_LE( bitmapSizes[i] );
914 if ( error )
915 goto Bail;
916
917 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
918
919 FT_TRACE4(( " %d-bit padding implies a size of %lu\n",
920 8 << i, bitmapSizes[i] ));
921 }
922
923 FT_TRACE4(( " %lu bitmaps, using %d-bit padding\n",
924 nbitmaps,
925 8 << PCF_GLYPH_PAD_INDEX( format ) ));
926 FT_TRACE4(( " bitmap size: %lu\n", sizebitmaps ));
927
928 FT_UNUSED( sizebitmaps ); /* only used for debugging */
929
930 face->bitmapsFormat = format;
931
932 Bail:
933 return error;
934 }
935
936
937 /*
938 * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
939 * is the same as a character code in FreeType speak.
940 */
941#define PCF_ENC_SIZE 10
942
943 static
944 const FT_Frame_Field pcf_enc_header[] =
945 {
946#undef FT_STRUCTURE
947#define FT_STRUCTURE PCF_EncRec
948
949 FT_FRAME_START( PCF_ENC_SIZE ),
950 FT_FRAME_USHORT_LE( firstCol ),
951 FT_FRAME_USHORT_LE( lastCol ),
952 FT_FRAME_USHORT_LE( firstRow ),
953 FT_FRAME_USHORT_LE( lastRow ),
954 FT_FRAME_USHORT_LE( defaultChar ),
955 FT_FRAME_END
956 };
957
958
959 static
960 const FT_Frame_Field pcf_enc_msb_header[] =
961 {
962#undef FT_STRUCTURE
963#define FT_STRUCTURE PCF_EncRec
964
965 FT_FRAME_START( PCF_ENC_SIZE ),
966 FT_FRAME_USHORT( firstCol ),
967 FT_FRAME_USHORT( lastCol ),
968 FT_FRAME_USHORT( firstRow ),
969 FT_FRAME_USHORT( lastRow ),
970 FT_FRAME_USHORT( defaultChar ),
971 FT_FRAME_END
972 };
973
974
975 static FT_Error
976 pcf_get_encodings( FT_Stream stream,
977 PCF_Face face )
978 {
979 FT_Error error;
980 FT_Memory memory = FT_FACE( face )->memory;
981 FT_ULong format, size;
982 PCF_Enc enc = &face->enc;
983 FT_ULong nencoding;
984 FT_UShort* offset;
985 FT_UShort defaultCharRow, defaultCharCol;
986 FT_UShort encodingOffset, defaultCharEncodingOffset;
987 FT_UShort i, j;
988 FT_Byte* pos;
989
990
991 error = pcf_seek_to_table_type( stream,
992 face->toc.tables,
993 face->toc.count,
994 PCF_BDF_ENCODINGS,
995 &format,
996 &size );
997 if ( error )
998 goto Bail;
999
1000 if ( FT_READ_ULONG_LE( format ) )
1001 goto Bail;
1002
1003 FT_TRACE4(( "pcf_get_encodings:\n" ));
1004 FT_TRACE4(( " format: 0x%lX (%s)\n",
1005 format,
1006 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
1007
1008 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
1009 !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS ) )
1010 return FT_THROW( Invalid_File_Format );
1011
1012 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1013 {
1014 if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) )
1015 goto Bail;
1016 }
1017 else
1018 {
1019 if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) )
1020 goto Bail;
1021 }
1022
1023 FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n",
1024 enc->firstCol, enc->lastCol ));
1025 FT_TRACE4(( " firstRow 0x%X, lastRow 0x%X\n",
1026 enc->firstRow, enc->lastRow ));
1027 FT_TRACE4(( " defaultChar 0x%X\n",
1028 enc->defaultChar ));
1029
1030 /* sanity checks; we limit numbers of rows and columns to 256 */
1031 if ( enc->firstCol > enc->lastCol ||
1032 enc->lastCol > 0xFF ||
1033 enc->firstRow > enc->lastRow ||
1034 enc->lastRow > 0xFF )
1035 return FT_THROW( Invalid_Table );
1036
1037 FT_TRACE5(( "\n" ));
1038
1039 defaultCharRow = enc->defaultChar >> 8;
1040 defaultCharCol = enc->defaultChar & 0xFF;
1041
1042 /* validate default character */
1043 if ( defaultCharRow < enc->firstRow ||
1044 defaultCharRow > enc->lastRow ||
1045 defaultCharCol < enc->firstCol ||
1046 defaultCharCol > enc->lastCol )
1047 {
1048 enc->defaultChar = enc->firstRow * 256U + enc->firstCol;
1049 FT_TRACE0(( "pcf_get_encodings:"
1050 " Invalid default character set to %u\n",
1051 enc->defaultChar ));
1052
1053 defaultCharRow = enc->firstRow;
1054 defaultCharCol = enc->firstCol;
1055 }
1056
1057 nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) *
1058 (FT_ULong)( enc->lastRow - enc->firstRow + 1 );
1059
1060 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
1061 if ( error )
1062 goto Bail;
1063
1064 /*
1065 * FreeType mandates that glyph index 0 is the `undefined glyph', which
1066 * PCF calls the `default character'. However, FreeType needs glyph
1067 * index 0 to be used for the undefined glyph only, which is is not the
1068 * case for PCF. For this reason, we add one slot for glyph index 0 and
1069 * simply copy the default character to it.
1070 *
1071 * `stream->cursor' still points to the beginning of the frame; we can
1072 * thus easily get the offset to the default character.
1073 */
1074 pos = stream->cursor +
1075 2 * ( ( defaultCharRow - enc->firstRow ) *
1076 ( enc->lastCol - enc->firstCol + 1 ) +
1077 defaultCharCol - enc->firstCol );
1078
1079 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1080 defaultCharEncodingOffset = FT_PEEK_USHORT( pos );
1081 else
1082 defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos );
1083
1084 if ( defaultCharEncodingOffset == 0xFFFF )
1085 {
1086 FT_TRACE0(( "pcf_get_encodings:"
1087 " No glyph for default character,\n" ));
1088 FT_TRACE0(( " "
1089 " setting it to the first glyph of the font\n" ));
1090 defaultCharEncodingOffset = 1;
1091 }
1092 else
1093 {
1094 defaultCharEncodingOffset++;
1095
1096 if ( defaultCharEncodingOffset >= face->nmetrics )
1097 {
1098 FT_TRACE0(( "pcf_get_encodings:"
1099 " Invalid glyph index for default character,\n" ));
1100 FT_TRACE0(( " "
1101 " setting it to the first glyph of the font\n" ));
1102 defaultCharEncodingOffset = 1;
1103 }
1104 }
1105
1106 /* copy metrics of default character to index 0 */
1107 face->metrics[0] = face->metrics[defaultCharEncodingOffset];
1108
1109 if ( FT_QNEW_ARRAY( enc->offset, nencoding ) )
1110 goto Bail;
1111
1112 /* now loop over all values */
1113 offset = enc->offset;
1114 for ( i = enc->firstRow; i <= enc->lastRow; i++ )
1115 {
1116 for ( j = enc->firstCol; j <= enc->lastCol; j++ )
1117 {
1118 /* X11's reference implementation uses the equivalent to */
1119 /* `FT_GET_SHORT', however PCF fonts with more than 32768 */
1120 /* characters (e.g., `unifont.pcf') clearly show that an */
1121 /* unsigned value is needed. */
1122 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1123 encodingOffset = FT_GET_USHORT();
1124 else
1125 encodingOffset = FT_GET_USHORT_LE();
1126
1127 /* everything is off by 1 due to the artificial glyph 0 */
1128 *offset++ = encodingOffset == 0xFFFF ? 0xFFFF
1129 : encodingOffset + 1;
1130 }
1131 }
1132 FT_Stream_ExitFrame( stream );
1133
1134 Bail:
1135 return error;
1136 }
1137
1138
1139 static
1140 const FT_Frame_Field pcf_accel_header[] =
1141 {
1142#undef FT_STRUCTURE
1143#define FT_STRUCTURE PCF_AccelRec
1144
1145 FT_FRAME_START( 20 ),
1146 FT_FRAME_BYTE ( noOverlap ),
1147 FT_FRAME_BYTE ( constantMetrics ),
1148 FT_FRAME_BYTE ( terminalFont ),
1149 FT_FRAME_BYTE ( constantWidth ),
1150 FT_FRAME_BYTE ( inkInside ),
1151 FT_FRAME_BYTE ( inkMetrics ),
1152 FT_FRAME_BYTE ( drawDirection ),
1153 FT_FRAME_SKIP_BYTES( 1 ),
1154 FT_FRAME_LONG_LE ( fontAscent ),
1155 FT_FRAME_LONG_LE ( fontDescent ),
1156 FT_FRAME_LONG_LE ( maxOverlap ),
1157 FT_FRAME_END
1158 };
1159
1160
1161 static
1162 const FT_Frame_Field pcf_accel_msb_header[] =
1163 {
1164#undef FT_STRUCTURE
1165#define FT_STRUCTURE PCF_AccelRec
1166
1167 FT_FRAME_START( 20 ),
1168 FT_FRAME_BYTE ( noOverlap ),
1169 FT_FRAME_BYTE ( constantMetrics ),
1170 FT_FRAME_BYTE ( terminalFont ),
1171 FT_FRAME_BYTE ( constantWidth ),
1172 FT_FRAME_BYTE ( inkInside ),
1173 FT_FRAME_BYTE ( inkMetrics ),
1174 FT_FRAME_BYTE ( drawDirection ),
1175 FT_FRAME_SKIP_BYTES( 1 ),
1176 FT_FRAME_LONG ( fontAscent ),
1177 FT_FRAME_LONG ( fontDescent ),
1178 FT_FRAME_LONG ( maxOverlap ),
1179 FT_FRAME_END
1180 };
1181
1182
1183 static FT_Error
1184 pcf_get_accel( FT_Stream stream,
1185 PCF_Face face,
1186 FT_ULong type )
1187 {
1188 FT_ULong format, size;
1189 FT_Error error;
1190 PCF_Accel accel = &face->accel;
1191
1192
1193 error = pcf_seek_to_table_type( stream,
1194 face->toc.tables,
1195 face->toc.count,
1196 type,
1197 &format,
1198 &size );
1199 if ( error )
1200 goto Bail;
1201
1202 if ( FT_READ_ULONG_LE( format ) )
1203 goto Bail;
1204
1205 FT_TRACE4(( "pcf_get_accel%s:\n",
1206 type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)"
1207 : "" ));
1208 FT_TRACE4(( " format: 0x%lX (%s, %s)\n",
1209 format,
1210 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
1211 PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ?
1212 "accelerated" : "not accelerated" ));
1213
1214 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
1215 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1216 goto Bail;
1217
1218 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1219 {
1220 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
1221 goto Bail;
1222 }
1223 else
1224 {
1225 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
1226 goto Bail;
1227 }
1228
1229 FT_TRACE5(( " noOverlap=%s, constantMetrics=%s,"
1230 " terminalFont=%s, constantWidth=%s\n",
1231 accel->noOverlap ? "yes" : "no",
1232 accel->constantMetrics ? "yes" : "no",
1233 accel->terminalFont ? "yes" : "no",
1234 accel->constantWidth ? "yes" : "no" ));
1235 FT_TRACE5(( " inkInside=%s, inkMetrics=%s, drawDirection=%s\n",
1236 accel->inkInside ? "yes" : "no",
1237 accel->inkMetrics ? "yes" : "no",
1238 accel->drawDirection ? "RTL" : "LTR" ));
1239 FT_TRACE5(( " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n",
1240 accel->fontAscent,
1241 accel->fontDescent,
1242 accel->maxOverlap ));
1243
1244 /* sanity checks */
1245 if ( FT_ABS( accel->fontAscent ) > 0x7FFF )
1246 {
1247 accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF;
1248 FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n",
1249 accel->fontAscent ));
1250 }
1251 if ( FT_ABS( accel->fontDescent ) > 0x7FFF )
1252 {
1253 accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF;
1254 FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n",
1255 accel->fontDescent ));
1256 }
1257
1258 FT_TRACE5(( " minbounds:" ));
1259 error = pcf_get_metric( stream,
1260 format & ( ~PCF_FORMAT_MASK ),
1261 &(accel->minbounds) );
1262 if ( error )
1263 goto Bail;
1264
1265 FT_TRACE5(( " maxbounds:" ));
1266 error = pcf_get_metric( stream,
1267 format & ( ~PCF_FORMAT_MASK ),
1268 &(accel->maxbounds) );
1269 if ( error )
1270 goto Bail;
1271
1272 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1273 {
1274 FT_TRACE5(( " ink minbounds:" ));
1275 error = pcf_get_metric( stream,
1276 format & ( ~PCF_FORMAT_MASK ),
1277 &(accel->ink_minbounds) );
1278 if ( error )
1279 goto Bail;
1280
1281 FT_TRACE5(( " ink maxbounds:" ));
1282 error = pcf_get_metric( stream,
1283 format & ( ~PCF_FORMAT_MASK ),
1284 &(accel->ink_maxbounds) );
1285 if ( error )
1286 goto Bail;
1287 }
1288 else
1289 {
1290 accel->ink_minbounds = accel->minbounds;
1291 accel->ink_maxbounds = accel->maxbounds;
1292 }
1293
1294 Bail:
1295 return error;
1296 }
1297
1298
1299 static FT_Error
1300 pcf_interpret_style( PCF_Face pcf )
1301 {
1302 FT_Error error = FT_Err_Ok;
1303 FT_Face face = FT_FACE( pcf );
1304 FT_Memory memory = face->memory;
1305
1306 PCF_Property prop;
1307
1308 const char* strings[4] = { NULL, NULL, NULL, NULL };
1309 size_t lengths[4], nn, len;
1310
1311
1312 face->style_flags = 0;
1313
1314 prop = pcf_find_property( pcf, "SLANT" );
1315 if ( prop && prop->isString &&
1316 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1317 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1318 {
1319 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1320 strings[2] = ( *(prop->value.atom) == 'O' ||
1321 *(prop->value.atom) == 'o' ) ? "Oblique"
1322 : "Italic";
1323 }
1324
1325 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1326 if ( prop && prop->isString &&
1327 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1328 {
1329 face->style_flags |= FT_STYLE_FLAG_BOLD;
1330 strings[1] = "Bold";
1331 }
1332
1333 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1334 if ( prop && prop->isString &&
1335 *(prop->value.atom) &&
1336 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1337 strings[3] = (const char*)( prop->value.atom );
1338
1339 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1340 if ( prop && prop->isString &&
1341 *(prop->value.atom) &&
1342 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1343 strings[0] = (const char*)( prop->value.atom );
1344
1345 for ( len = 0, nn = 0; nn < 4; nn++ )
1346 {
1347 lengths[nn] = 0;
1348 if ( strings[nn] )
1349 {
1350 lengths[nn] = ft_strlen( strings[nn] );
1351 len += lengths[nn] + 1;
1352 }
1353 }
1354
1355 if ( len == 0 )
1356 {
1357 strings[0] = "Regular";
1358 lengths[0] = ft_strlen( strings[0] );
1359 len = lengths[0] + 1;
1360 }
1361
1362 {
1363 char* s;
1364
1365
1366 if ( FT_QALLOC( face->style_name, len ) )
1367 return error;
1368
1369 s = face->style_name;
1370
1371 for ( nn = 0; nn < 4; nn++ )
1372 {
1373 const char* src = strings[nn];
1374
1375
1376 len = lengths[nn];
1377
1378 if ( !src )
1379 continue;
1380
1381 /* separate elements with a space */
1382 if ( s != face->style_name )
1383 *s++ = ' ';
1384
1385 ft_memcpy( s, src, len );
1386
1387 /* need to convert spaces to dashes for */
1388 /* add_style_name and setwidth_name */
1389 if ( nn == 0 || nn == 3 )
1390 {
1391 size_t mm;
1392
1393
1394 for ( mm = 0; mm < len; mm++ )
1395 if ( s[mm] == ' ' )
1396 s[mm] = '-';
1397 }
1398
1399 s += len;
1400 }
1401 *s = 0;
1402 }
1403
1404 return error;
1405 }
1406
1407
1408 FT_LOCAL_DEF( FT_Error )
1409 pcf_load_font( FT_Stream stream,
1410 PCF_Face face,
1411 FT_Long face_index )
1412 {
1413 FT_Face root = FT_FACE( face );
1414 FT_Error error;
1415 FT_Memory memory = FT_FACE( face )->memory;
1416 FT_Bool hasBDFAccelerators;
1417
1418
1419 error = pcf_read_TOC( stream, face );
1420 if ( error )
1421 goto Exit;
1422
1423 root->num_faces = 1;
1424 root->face_index = 0;
1425
1426 /* If we are performing a simple font format check, exit immediately. */
1427 if ( face_index < 0 )
1428 return FT_Err_Ok;
1429
1430 error = pcf_get_properties( stream, face );
1431 if ( error )
1432 goto Exit;
1433
1434 /* Use the old accelerators if no BDF accelerators are in the file. */
1435 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1436 face->toc.count,
1437 PCF_BDF_ACCELERATORS );
1438 if ( !hasBDFAccelerators )
1439 {
1440 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1441 if ( error )
1442 goto Exit;
1443 }
1444
1445 /* metrics */
1446 error = pcf_get_metrics( stream, face );
1447 if ( error )
1448 goto Exit;
1449
1450 /* bitmaps */
1451 error = pcf_get_bitmaps( stream, face );
1452 if ( error )
1453 goto Exit;
1454
1455 /* encodings */
1456 error = pcf_get_encodings( stream, face );
1457 if ( error )
1458 goto Exit;
1459
1460 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1461 if ( hasBDFAccelerators )
1462 {
1463 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1464 if ( error )
1465 goto Exit;
1466 }
1467
1468 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1469
1470 /* now construct the face object */
1471 {
1472 PCF_Property prop;
1473
1474
1475 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
1476 FT_FACE_FLAG_HORIZONTAL;
1477
1478 if ( face->accel.constantWidth )
1479 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1480
1481 if ( FT_SET_ERROR( pcf_interpret_style( face ) ) )
1482 goto Exit;
1483
1484 prop = pcf_find_property( face, "FAMILY_NAME" );
1485 if ( prop && prop->isString )
1486 {
1487
1488#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
1489
1490 PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face );
1491
1492
1493 if ( !driver->no_long_family_names )
1494 {
1495 /* Prepend the foundry name plus a space to the family name. */
1496 /* There are many fonts just called `Fixed' which look */
1497 /* completely different, and which have nothing to do with each */
1498 /* other. When selecting `Fixed' in KDE or Gnome one gets */
1499 /* results that appear rather random, the style changes often if */
1500 /* one changes the size and one cannot select some fonts at all. */
1501 /* */
1502 /* We also check whether we have `wide' characters; all put */
1503 /* together, we get family names like `Sony Fixed' or `Misc */
1504 /* Fixed Wide'. */
1505
1506 PCF_Property foundry_prop, point_size_prop, average_width_prop;
1507
1508 int l = ft_strlen( prop->value.atom ) + 1;
1509 int wide = 0;
1510
1511
1512 foundry_prop = pcf_find_property( face, "FOUNDRY" );
1513 point_size_prop = pcf_find_property( face, "POINT_SIZE" );
1514 average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1515
1516 if ( point_size_prop && average_width_prop )
1517 {
1518 if ( average_width_prop->value.l >= point_size_prop->value.l )
1519 {
1520 /* This font is at least square shaped or even wider */
1521 wide = 1;
1522 l += ft_strlen( " Wide" );
1523 }
1524 }
1525
1526 if ( foundry_prop && foundry_prop->isString )
1527 {
1528 l += ft_strlen( foundry_prop->value.atom ) + 1;
1529
1530 if ( FT_QALLOC( root->family_name, l ) )
1531 goto Exit;
1532
1533 ft_strcpy( root->family_name, foundry_prop->value.atom );
1534 ft_strcat( root->family_name, " " );
1535 ft_strcat( root->family_name, prop->value.atom );
1536 }
1537 else
1538 {
1539 if ( FT_QALLOC( root->family_name, l ) )
1540 goto Exit;
1541
1542 ft_strcpy( root->family_name, prop->value.atom );
1543 }
1544
1545 if ( wide )
1546 ft_strcat( root->family_name, " Wide" );
1547 }
1548 else
1549
1550#endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
1551
1552 {
1553 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1554 goto Exit;
1555 }
1556 }
1557 else
1558 root->family_name = NULL;
1559
1560 root->num_glyphs = (FT_Long)face->nmetrics;
1561
1562 root->num_fixed_sizes = 1;
1563 if ( FT_NEW( root->available_sizes ) )
1564 goto Exit;
1565
1566 {
1567 FT_Bitmap_Size* bsize = root->available_sizes;
1568 FT_Short resolution_x = 0, resolution_y = 0;
1569
1570
1571 /* for simplicity, we take absolute values of integer properties */
1572
1573#if 0
1574 bsize->height = face->accel.maxbounds.ascent << 6;
1575#endif
1576
1577#ifdef FT_DEBUG_LEVEL_TRACE
1578 if ( face->accel.fontAscent + face->accel.fontDescent < 0 )
1579 FT_TRACE0(( "pcf_load_font: negative height\n" ));
1580#endif
1581 if ( FT_ABS( face->accel.fontAscent +
1582 face->accel.fontDescent ) > 0x7FFF )
1583 {
1584 bsize->height = 0x7FFF;
1585 FT_TRACE0(( "pcf_load_font: clamping height to value %d\n",
1586 bsize->height ));
1587 }
1588 else
1589 bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent +
1590 face->accel.fontDescent ) );
1591
1592 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1593 if ( prop )
1594 {
1595#ifdef FT_DEBUG_LEVEL_TRACE
1596 if ( prop->value.l < 0 )
1597 FT_TRACE0(( "pcf_load_font: negative average width\n" ));
1598#endif
1599 if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) )
1600 {
1601 bsize->width = 0x7FFF;
1602 FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n",
1603 bsize->width ));
1604 }
1605 else
1606 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
1607 }
1608 else
1609 {
1610 /* this is a heuristical value */
1611 bsize->width = ( bsize->height * 2 + 1 ) / 3;
1612 }
1613
1614 prop = pcf_find_property( face, "POINT_SIZE" );
1615 if ( prop )
1616 {
1617#ifdef FT_DEBUG_LEVEL_TRACE
1618 if ( prop->value.l < 0 )
1619 FT_TRACE0(( "pcf_load_font: negative point size\n" ));
1620#endif
1621 /* convert from 722.7 decipoints to 72 points per inch */
1622 if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */
1623 {
1624 bsize->size = 0x7FFF;
1625 FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n",
1626 bsize->size ));
1627 }
1628 else
1629 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
1630 64 * 7200,
1631 72270L );
1632 }
1633
1634 prop = pcf_find_property( face, "PIXEL_SIZE" );
1635 if ( prop )
1636 {
1637#ifdef FT_DEBUG_LEVEL_TRACE
1638 if ( prop->value.l < 0 )
1639 FT_TRACE0(( "pcf_load_font: negative pixel size\n" ));
1640#endif
1641 if ( FT_ABS( prop->value.l ) > 0x7FFF )
1642 {
1643 bsize->y_ppem = 0x7FFF << 6;
1644 FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n",
1645 bsize->y_ppem ));
1646 }
1647 else
1648 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
1649 }
1650
1651 prop = pcf_find_property( face, "RESOLUTION_X" );
1652 if ( prop )
1653 {
1654#ifdef FT_DEBUG_LEVEL_TRACE
1655 if ( prop->value.l < 0 )
1656 FT_TRACE0(( "pcf_load_font: negative X resolution\n" ));
1657#endif
1658 if ( FT_ABS( prop->value.l ) > 0x7FFF )
1659 {
1660 resolution_x = 0x7FFF;
1661 FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n",
1662 resolution_x ));
1663 }
1664 else
1665 resolution_x = FT_ABS( (FT_Short)prop->value.l );
1666 }
1667
1668 prop = pcf_find_property( face, "RESOLUTION_Y" );
1669 if ( prop )
1670 {
1671#ifdef FT_DEBUG_LEVEL_TRACE
1672 if ( prop->value.l < 0 )
1673 FT_TRACE0(( "pcf_load_font: negative Y resolution\n" ));
1674#endif
1675 if ( FT_ABS( prop->value.l ) > 0x7FFF )
1676 {
1677 resolution_y = 0x7FFF;
1678 FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n",
1679 resolution_y ));
1680 }
1681 else
1682 resolution_y = FT_ABS( (FT_Short)prop->value.l );
1683 }
1684
1685 if ( bsize->y_ppem == 0 )
1686 {
1687 bsize->y_ppem = bsize->size;
1688 if ( resolution_y )
1689 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
1690 }
1691 if ( resolution_x && resolution_y )
1692 bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
1693 resolution_x,
1694 resolution_y );
1695 else
1696 bsize->x_ppem = bsize->y_ppem;
1697 }
1698
1699 /* set up charset */
1700 {
1701 PCF_Property charset_registry, charset_encoding;
1702
1703
1704 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1705 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1706
1707 if ( charset_registry && charset_registry->isString &&
1708 charset_encoding && charset_encoding->isString )
1709 {
1710 if ( FT_STRDUP( face->charset_encoding,
1711 charset_encoding->value.atom ) ||
1712 FT_STRDUP( face->charset_registry,
1713 charset_registry->value.atom ) )
1714 goto Exit;
1715 }
1716 }
1717 }
1718
1719 Exit:
1720 if ( error )
1721 {
1722 /* This is done to respect the behaviour of the original */
1723 /* PCF font driver. */
1724 error = FT_THROW( Invalid_File_Format );
1725 }
1726
1727 return error;
1728 }
1729
1730
1731/* END */
1732