* Sync up to trunk HEAD (r62502).
[reactos.git] / lib / 3rdparty / freetype / src / pcf / pcfread.c
1 /* pcfread.c
2
3 FreeType font driver for pcf fonts
4
5 Copyright 2000-2010, 2012, 2013 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 FT_THROW( 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 FT_THROW( Invalid_File_Format );
107
108 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
109 return FT_THROW( 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 FT_THROW( 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 FT_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 = FT_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 = FT_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 = FT_THROW( Invalid_Stream_Skip );
307 goto Fail;
308 }
309
310 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
311 {
312 error = FT_THROW( Invalid_Stream_Skip );
313 goto Fail;
314 }
315
316 *asize = tables[i].size;
317 *aformat = tables[i].format;
318
319 return FT_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 = NULL;
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 = FT_THROW( 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 = FT_THROW( 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 = FT_THROW( Invalid_Table );
495 goto Bail;
496 }
497
498 /* allocate one more byte so that we have a final null byte */
499 if ( FT_NEW_ARRAY( strings, string_size + 1 ) )
500 goto Bail;
501
502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
503 if ( error )
504 goto Bail;
505
506 if ( FT_NEW_ARRAY( properties, nprops ) )
507 goto Bail;
508
509 face->properties = properties;
510
511 for ( i = 0; i < nprops; i++ )
512 {
513 FT_Long name_offset = props[i].name;
514
515
516 if ( ( name_offset < 0 ) ||
517 ( (FT_ULong)name_offset > string_size ) )
518 {
519 error = FT_THROW( Invalid_Offset );
520 goto Bail;
521 }
522
523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
524 goto Bail;
525
526 FT_TRACE4(( " %s:", properties[i].name ));
527
528 properties[i].isString = props[i].isString;
529
530 if ( props[i].isString )
531 {
532 FT_Long value_offset = props[i].value;
533
534
535 if ( ( value_offset < 0 ) ||
536 ( (FT_ULong)value_offset > string_size ) )
537 {
538 error = FT_THROW( Invalid_Offset );
539 goto Bail;
540 }
541
542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
543 goto Bail;
544
545 FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
546 }
547 else
548 {
549 properties[i].value.l = props[i].value;
550
551 FT_TRACE4(( " %d\n", properties[i].value.l ));
552 }
553 }
554
555 error = FT_Err_Ok;
556
557 Bail:
558 FT_FREE( props );
559 FT_FREE( strings );
560
561 return error;
562 }
563
564
565 static FT_Error
566 pcf_get_metrics( FT_Stream stream,
567 PCF_Face face )
568 {
569 FT_Error error;
570 FT_Memory memory = FT_FACE( face )->memory;
571 FT_ULong format, size;
572 PCF_Metric metrics = 0;
573 FT_ULong nmetrics, i;
574
575
576 error = pcf_seek_to_table_type( stream,
577 face->toc.tables,
578 face->toc.count,
579 PCF_METRICS,
580 &format,
581 &size );
582 if ( error )
583 return error;
584
585 if ( FT_READ_ULONG_LE( format ) )
586 goto Bail;
587
588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
590 return FT_THROW( Invalid_File_Format );
591
592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
593 {
594 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
595 (void)FT_READ_ULONG( nmetrics );
596 else
597 (void)FT_READ_ULONG_LE( nmetrics );
598 }
599 else
600 {
601 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
602 (void)FT_READ_USHORT( nmetrics );
603 else
604 (void)FT_READ_USHORT_LE( nmetrics );
605 }
606 if ( error )
607 return FT_THROW( Invalid_File_Format );
608
609 face->nmetrics = nmetrics;
610
611 if ( !nmetrics )
612 return FT_THROW( Invalid_Table );
613
614 FT_TRACE4(( "pcf_get_metrics:\n" ));
615
616 FT_TRACE4(( " number of metrics: %d\n", nmetrics ));
617
618 /* rough estimate */
619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
620 {
621 if ( nmetrics > size / PCF_METRIC_SIZE )
622 return FT_THROW( Invalid_Table );
623 }
624 else
625 {
626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
627 return FT_THROW( Invalid_Table );
628 }
629
630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
631 return FT_THROW( Out_Of_Memory );
632
633 metrics = face->metrics;
634 for ( i = 0; i < nmetrics; i++ )
635 {
636 error = pcf_get_metric( stream, format, metrics + i );
637
638 metrics[i].bits = 0;
639
640 FT_TRACE5(( " idx %d: width=%d, "
641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
642 i,
643 ( metrics + i )->characterWidth,
644 ( metrics + i )->leftSideBearing,
645 ( metrics + i )->rightSideBearing,
646 ( metrics + i )->ascent,
647 ( metrics + i )->descent,
648 ( metrics + i )->attributes ));
649
650 if ( error )
651 break;
652 }
653
654 if ( error )
655 FT_FREE( face->metrics );
656
657 Bail:
658 return error;
659 }
660
661
662 static FT_Error
663 pcf_get_bitmaps( FT_Stream stream,
664 PCF_Face face )
665 {
666 FT_Error error;
667 FT_Memory memory = FT_FACE( face )->memory;
668 FT_Long* offsets = NULL;
669 FT_Long bitmapSizes[GLYPHPADOPTIONS];
670 FT_ULong format, size;
671 FT_ULong nbitmaps, i, sizebitmaps = 0;
672
673
674 error = pcf_seek_to_table_type( stream,
675 face->toc.tables,
676 face->toc.count,
677 PCF_BITMAPS,
678 &format,
679 &size );
680 if ( error )
681 return error;
682
683 error = FT_Stream_EnterFrame( stream, 8 );
684 if ( error )
685 return error;
686
687 format = FT_GET_ULONG_LE();
688 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
689 nbitmaps = FT_GET_ULONG();
690 else
691 nbitmaps = FT_GET_ULONG_LE();
692
693 FT_Stream_ExitFrame( stream );
694
695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
696 return FT_THROW( Invalid_File_Format );
697
698 FT_TRACE4(( "pcf_get_bitmaps:\n" ));
699
700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
701
702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
704 return FT_THROW( Invalid_File_Format );
705
706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
707 return error;
708
709 for ( i = 0; i < nbitmaps; i++ )
710 {
711 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
712 (void)FT_READ_LONG( offsets[i] );
713 else
714 (void)FT_READ_LONG_LE( offsets[i] );
715
716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n",
717 i, offsets[i], offsets[i] ));
718 }
719 if ( error )
720 goto Bail;
721
722 for ( i = 0; i < GLYPHPADOPTIONS; i++ )
723 {
724 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
725 (void)FT_READ_LONG( bitmapSizes[i] );
726 else
727 (void)FT_READ_LONG_LE( bitmapSizes[i] );
728 if ( error )
729 goto Bail;
730
731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
732
733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
734 }
735
736 FT_TRACE4(( " %d bitmaps, padding index %ld\n",
737 nbitmaps,
738 PCF_GLYPH_PAD_INDEX( format ) ));
739 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps ));
740
741 FT_UNUSED( sizebitmaps ); /* only used for debugging */
742
743 for ( i = 0; i < nbitmaps; i++ )
744 {
745 /* rough estimate */
746 if ( ( offsets[i] < 0 ) ||
747 ( (FT_ULong)offsets[i] > size ) )
748 {
749 FT_TRACE0(( "pcf_get_bitmaps:"
750 " invalid offset to bitmap data of glyph %d\n", i ));
751 }
752 else
753 face->metrics[i].bits = stream->pos + offsets[i];
754 }
755
756 face->bitmapsFormat = format;
757
758 Bail:
759 FT_FREE( offsets );
760 return error;
761 }
762
763
764 static FT_Error
765 pcf_get_encodings( FT_Stream stream,
766 PCF_Face face )
767 {
768 FT_Error error;
769 FT_Memory memory = FT_FACE( face )->memory;
770 FT_ULong format, size;
771 int firstCol, lastCol;
772 int firstRow, lastRow;
773 int nencoding, encodingOffset;
774 int i, j, k;
775 PCF_Encoding encoding = NULL;
776
777
778 error = pcf_seek_to_table_type( stream,
779 face->toc.tables,
780 face->toc.count,
781 PCF_BDF_ENCODINGS,
782 &format,
783 &size );
784 if ( error )
785 return error;
786
787 error = FT_Stream_EnterFrame( stream, 14 );
788 if ( error )
789 return error;
790
791 format = FT_GET_ULONG_LE();
792
793 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
794 {
795 firstCol = FT_GET_SHORT();
796 lastCol = FT_GET_SHORT();
797 firstRow = FT_GET_SHORT();
798 lastRow = FT_GET_SHORT();
799 face->defaultChar = FT_GET_SHORT();
800 }
801 else
802 {
803 firstCol = FT_GET_SHORT_LE();
804 lastCol = FT_GET_SHORT_LE();
805 firstRow = FT_GET_SHORT_LE();
806 lastRow = FT_GET_SHORT_LE();
807 face->defaultChar = FT_GET_SHORT_LE();
808 }
809
810 FT_Stream_ExitFrame( stream );
811
812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
813 return FT_THROW( Invalid_File_Format );
814
815 FT_TRACE4(( "pdf_get_encodings:\n" ));
816
817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
818 firstCol, lastCol, firstRow, lastRow ));
819
820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
821
822 if ( FT_NEW_ARRAY( encoding, nencoding ) )
823 return FT_THROW( Out_Of_Memory );
824
825 error = FT_Stream_EnterFrame( stream, 2 * nencoding );
826 if ( error )
827 goto Bail;
828
829 k = 0;
830 for ( i = firstRow; i <= lastRow; i++ )
831 {
832 for ( j = firstCol; j <= lastCol; j++ )
833 {
834 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
835 encodingOffset = FT_GET_SHORT();
836 else
837 encodingOffset = FT_GET_SHORT_LE();
838
839 if ( encodingOffset != -1 )
840 {
841 encoding[k].enc = i * 256 + j;
842 encoding[k].glyph = (FT_Short)encodingOffset;
843
844 FT_TRACE5(( " code %d (0x%04X): idx %d\n",
845 encoding[k].enc, encoding[k].enc, encoding[k].glyph ));
846
847 k++;
848 }
849 }
850 }
851 FT_Stream_ExitFrame( stream );
852
853 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) )
854 goto Bail;
855
856 face->nencodings = k;
857 face->encodings = encoding;
858
859 return error;
860
861 Bail:
862 FT_FREE( encoding );
863 return error;
864 }
865
866
867 static
868 const FT_Frame_Field pcf_accel_header[] =
869 {
870 #undef FT_STRUCTURE
871 #define FT_STRUCTURE PCF_AccelRec
872
873 FT_FRAME_START( 20 ),
874 FT_FRAME_BYTE ( noOverlap ),
875 FT_FRAME_BYTE ( constantMetrics ),
876 FT_FRAME_BYTE ( terminalFont ),
877 FT_FRAME_BYTE ( constantWidth ),
878 FT_FRAME_BYTE ( inkInside ),
879 FT_FRAME_BYTE ( inkMetrics ),
880 FT_FRAME_BYTE ( drawDirection ),
881 FT_FRAME_SKIP_BYTES( 1 ),
882 FT_FRAME_LONG_LE ( fontAscent ),
883 FT_FRAME_LONG_LE ( fontDescent ),
884 FT_FRAME_LONG_LE ( maxOverlap ),
885 FT_FRAME_END
886 };
887
888
889 static
890 const FT_Frame_Field pcf_accel_msb_header[] =
891 {
892 #undef FT_STRUCTURE
893 #define FT_STRUCTURE PCF_AccelRec
894
895 FT_FRAME_START( 20 ),
896 FT_FRAME_BYTE ( noOverlap ),
897 FT_FRAME_BYTE ( constantMetrics ),
898 FT_FRAME_BYTE ( terminalFont ),
899 FT_FRAME_BYTE ( constantWidth ),
900 FT_FRAME_BYTE ( inkInside ),
901 FT_FRAME_BYTE ( inkMetrics ),
902 FT_FRAME_BYTE ( drawDirection ),
903 FT_FRAME_SKIP_BYTES( 1 ),
904 FT_FRAME_LONG ( fontAscent ),
905 FT_FRAME_LONG ( fontDescent ),
906 FT_FRAME_LONG ( maxOverlap ),
907 FT_FRAME_END
908 };
909
910
911 static FT_Error
912 pcf_get_accel( FT_Stream stream,
913 PCF_Face face,
914 FT_ULong type )
915 {
916 FT_ULong format, size;
917 FT_Error error;
918 PCF_Accel accel = &face->accel;
919
920
921 error = pcf_seek_to_table_type( stream,
922 face->toc.tables,
923 face->toc.count,
924 type,
925 &format,
926 &size );
927 if ( error )
928 goto Bail;
929
930 if ( FT_READ_ULONG_LE( format ) )
931 goto Bail;
932
933 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
934 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
935 goto Bail;
936
937 if ( PCF_BYTE_ORDER( format ) == MSBFirst )
938 {
939 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
940 goto Bail;
941 }
942 else
943 {
944 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
945 goto Bail;
946 }
947
948 error = pcf_get_metric( stream,
949 format & ( ~PCF_FORMAT_MASK ),
950 &(accel->minbounds) );
951 if ( error )
952 goto Bail;
953
954 error = pcf_get_metric( stream,
955 format & ( ~PCF_FORMAT_MASK ),
956 &(accel->maxbounds) );
957 if ( error )
958 goto Bail;
959
960 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
961 {
962 error = pcf_get_metric( stream,
963 format & ( ~PCF_FORMAT_MASK ),
964 &(accel->ink_minbounds) );
965 if ( error )
966 goto Bail;
967
968 error = pcf_get_metric( stream,
969 format & ( ~PCF_FORMAT_MASK ),
970 &(accel->ink_maxbounds) );
971 if ( error )
972 goto Bail;
973 }
974 else
975 {
976 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
977 accel->ink_maxbounds = accel->maxbounds;
978 }
979
980 Bail:
981 return error;
982 }
983
984
985 static FT_Error
986 pcf_interpret_style( PCF_Face pcf )
987 {
988 FT_Error error = FT_Err_Ok;
989 FT_Face face = FT_FACE( pcf );
990 FT_Memory memory = face->memory;
991
992 PCF_Property prop;
993
994 size_t nn, len;
995 char* strings[4] = { NULL, NULL, NULL, NULL };
996 size_t lengths[4];
997
998
999 face->style_flags = 0;
1000
1001 prop = pcf_find_property( pcf, "SLANT" );
1002 if ( prop && prop->isString &&
1003 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1004 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1005 {
1006 face->style_flags |= FT_STYLE_FLAG_ITALIC;
1007 strings[2] = ( *(prop->value.atom) == 'O' ||
1008 *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1009 : (char *)"Italic";
1010 }
1011
1012 prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1013 if ( prop && prop->isString &&
1014 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1015 {
1016 face->style_flags |= FT_STYLE_FLAG_BOLD;
1017 strings[1] = (char*)"Bold";
1018 }
1019
1020 prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1021 if ( prop && prop->isString &&
1022 *(prop->value.atom) &&
1023 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1024 strings[3] = (char*)( prop->value.atom );
1025
1026 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1027 if ( prop && prop->isString &&
1028 *(prop->value.atom) &&
1029 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1030 strings[0] = (char*)( prop->value.atom );
1031
1032 for ( len = 0, nn = 0; nn < 4; nn++ )
1033 {
1034 lengths[nn] = 0;
1035 if ( strings[nn] )
1036 {
1037 lengths[nn] = ft_strlen( strings[nn] );
1038 len += lengths[nn] + 1;
1039 }
1040 }
1041
1042 if ( len == 0 )
1043 {
1044 strings[0] = (char*)"Regular";
1045 lengths[0] = ft_strlen( strings[0] );
1046 len = lengths[0] + 1;
1047 }
1048
1049 {
1050 char* s;
1051
1052
1053 if ( FT_ALLOC( face->style_name, len ) )
1054 return error;
1055
1056 s = face->style_name;
1057
1058 for ( nn = 0; nn < 4; nn++ )
1059 {
1060 char* src = strings[nn];
1061
1062
1063 len = lengths[nn];
1064
1065 if ( src == NULL )
1066 continue;
1067
1068 /* separate elements with a space */
1069 if ( s != face->style_name )
1070 *s++ = ' ';
1071
1072 ft_memcpy( s, src, len );
1073
1074 /* need to convert spaces to dashes for */
1075 /* add_style_name and setwidth_name */
1076 if ( nn == 0 || nn == 3 )
1077 {
1078 size_t mm;
1079
1080
1081 for ( mm = 0; mm < len; mm++ )
1082 if ( s[mm] == ' ' )
1083 s[mm] = '-';
1084 }
1085
1086 s += len;
1087 }
1088 *s = 0;
1089 }
1090
1091 return error;
1092 }
1093
1094
1095 FT_LOCAL_DEF( FT_Error )
1096 pcf_load_font( FT_Stream stream,
1097 PCF_Face face )
1098 {
1099 FT_Error error;
1100 FT_Memory memory = FT_FACE( face )->memory;
1101 FT_Bool hasBDFAccelerators;
1102
1103
1104 error = pcf_read_TOC( stream, face );
1105 if ( error )
1106 goto Exit;
1107
1108 error = pcf_get_properties( stream, face );
1109 if ( error )
1110 goto Exit;
1111
1112 /* Use the old accelerators if no BDF accelerators are in the file. */
1113 hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1114 face->toc.count,
1115 PCF_BDF_ACCELERATORS );
1116 if ( !hasBDFAccelerators )
1117 {
1118 error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1119 if ( error )
1120 goto Exit;
1121 }
1122
1123 /* metrics */
1124 error = pcf_get_metrics( stream, face );
1125 if ( error )
1126 goto Exit;
1127
1128 /* bitmaps */
1129 error = pcf_get_bitmaps( stream, face );
1130 if ( error )
1131 goto Exit;
1132
1133 /* encodings */
1134 error = pcf_get_encodings( stream, face );
1135 if ( error )
1136 goto Exit;
1137
1138 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1139 if ( hasBDFAccelerators )
1140 {
1141 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1142 if ( error )
1143 goto Exit;
1144 }
1145
1146 /* XXX: TO DO: inkmetrics and glyph_names are missing */
1147
1148 /* now construct the face object */
1149 {
1150 FT_Face root = FT_FACE( face );
1151 PCF_Property prop;
1152
1153
1154 root->num_faces = 1;
1155 root->face_index = 0;
1156 root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1157 FT_FACE_FLAG_HORIZONTAL |
1158 FT_FACE_FLAG_FAST_GLYPHS;
1159
1160 if ( face->accel.constantWidth )
1161 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1162
1163 if ( ( error = pcf_interpret_style( face ) ) != 0 )
1164 goto Exit;
1165
1166 prop = pcf_find_property( face, "FAMILY_NAME" );
1167 if ( prop && prop->isString )
1168 {
1169 if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1170 goto Exit;
1171 }
1172 else
1173 root->family_name = NULL;
1174
1175 /*
1176 * Note: We shift all glyph indices by +1 since we must
1177 * respect the convention that glyph 0 always corresponds
1178 * to the `missing glyph'.
1179 *
1180 * This implies bumping the number of `available' glyphs by 1.
1181 */
1182 root->num_glyphs = face->nmetrics + 1;
1183
1184 root->num_fixed_sizes = 1;
1185 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1186 goto Exit;
1187
1188 {
1189 FT_Bitmap_Size* bsize = root->available_sizes;
1190 FT_Short resolution_x = 0, resolution_y = 0;
1191
1192
1193 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1194
1195 #if 0
1196 bsize->height = face->accel.maxbounds.ascent << 6;
1197 #endif
1198 bsize->height = (FT_Short)( face->accel.fontAscent +
1199 face->accel.fontDescent );
1200
1201 prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1202 if ( prop )
1203 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1204 else
1205 bsize->width = (FT_Short)( bsize->height * 2/3 );
1206
1207 prop = pcf_find_property( face, "POINT_SIZE" );
1208 if ( prop )
1209 /* convert from 722.7 decipoints to 72 points per inch */
1210 bsize->size =
1211 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1212
1213 prop = pcf_find_property( face, "PIXEL_SIZE" );
1214 if ( prop )
1215 bsize->y_ppem = (FT_Short)prop->value.l << 6;
1216
1217 prop = pcf_find_property( face, "RESOLUTION_X" );
1218 if ( prop )
1219 resolution_x = (FT_Short)prop->value.l;
1220
1221 prop = pcf_find_property( face, "RESOLUTION_Y" );
1222 if ( prop )
1223 resolution_y = (FT_Short)prop->value.l;
1224
1225 if ( bsize->y_ppem == 0 )
1226 {
1227 bsize->y_ppem = bsize->size;
1228 if ( resolution_y )
1229 bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1230 }
1231 if ( resolution_x && resolution_y )
1232 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1233 else
1234 bsize->x_ppem = bsize->y_ppem;
1235 }
1236
1237 /* set up charset */
1238 {
1239 PCF_Property charset_registry = 0, charset_encoding = 0;
1240
1241
1242 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1243 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1244
1245 if ( charset_registry && charset_registry->isString &&
1246 charset_encoding && charset_encoding->isString )
1247 {
1248 if ( FT_STRDUP( face->charset_encoding,
1249 charset_encoding->value.atom ) ||
1250 FT_STRDUP( face->charset_registry,
1251 charset_registry->value.atom ) )
1252 goto Exit;
1253 }
1254 }
1255 }
1256
1257 Exit:
1258 if ( error )
1259 {
1260 /* This is done to respect the behaviour of the original */
1261 /* PCF font driver. */
1262 error = FT_THROW( Invalid_File_Format );
1263 }
1264
1265 return error;
1266 }
1267
1268
1269 /* END */