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