contrib/OWB: add correct SDL dependency, fix compilers used
[AROS-Contrib.git] / freetype1 / pascal / lib / ttload.pas
bloba7f234a1257477d30b4275b5c0a7ee2cd285905d
1 (*******************************************************************
3 * TTLoad.Pas 1.0
5 * TrueType Tables loaders
7 * Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
9 * This file is part of the FreeType project, and may only be used
10 * modified and distributed under the terms of the FreeType project
11 * license, LICENSE.TXT. By continuing to use, modify or distribute
12 * this file you indicate that you have read the license and
13 * understand and accept it fully.
16 * Difference between 1.0 and 1.1 : HUGE !!
18 * - Changed the load model to get in touch with TTFile 1.1
19 * - Now loads one whole resident table in one call
20 * - defined resident and instance records/data
22 ******************************************************************)
24 Unit TTLoad;
26 interface
28 uses FreeType, TTTypes, TTTables, TTCMap, TTObjs;
30 function LookUp_TrueType_Table( face : PFace;
31 aTag : string ) : int;
33 function Load_TrueType_Directory( face : PFace;
34 faceIndex : Int ) : TError;
36 function Load_TrueType_MaxProfile( face : PFace ) : TError;
37 function Load_TrueType_Header ( face : PFace ) : TError;
38 function Load_TrueType_Locations ( face : PFace ) : TError;
39 function Load_TrueType_CVT ( face : PFace ) : TError;
40 function Load_TrueType_CMap ( face : PFace ) : TError;
41 function Load_TrueType_Gasp ( face : PFace ) : TError;
42 function Load_TrueType_Names ( face : PFace ) : TError;
43 function Load_TrueType_Programs ( face : PFace ) : TError;
44 function Load_trueType_Postscript( face : PFace ) : TError;
45 function Load_TrueType_OS2 ( face : PFace ) : TError;
46 function Load_TrueType_HDMX ( face : PFace ) : TError;
48 function Load_TrueType_Metrics_Header( face : PFace;
49 vertical : Boolean ) : TError;
51 function Load_TrueType_Any( face : PFace;
52 tag : longint;
53 offset : longint;
54 var buffer;
55 var length : longint ) : TError;
57 implementation
59 uses TTError, TTMemory, TTFile, TTCalc;
61 (* Composite glyph decoding flags *)
63 (*******************************************************************
65 * Function : LookUp_TrueType_Table
67 * Description : Looks for a TrueType table by name
69 * Input : face resident table to look for
70 * aTag searched tag
72 * Output : index of table if found, -1 otherwise.
74 ******************************************************************)
76 function LookUp_TrueType_Table( face : PFace;
77 aTag : string ) : int;
78 var
79 ltag : Long;
80 i : int;
81 begin
82 ltag := (Long(ord(aTag[1])) shl 24) + (Long(ord(aTag[2])) shl 16) +
83 (Long(ord(aTag[3])) shl 8 ) + Long(ord(aTag[4]));
85 for i := 0 to face^.numTables-1 do
86 begin
88 if face^.dirTables^[i].Tag = lTag then
89 begin
90 LookUp_TrueType_Table := i;
91 exit;
92 end
93 end;
95 (* couldn't find the table *)
96 LookUp_TrueType_Table := -1;
97 end;
100 function LookUp_Mandatory_Table( face : PFace;
101 aTag : string ) : int;
103 table : int;
104 begin
105 table := LookUp_TrueType_Table( face, aTag );
106 if table < 0 then
107 error := TT_Err_Table_Missing;
109 LookUp_Mandatory_Table := table;
110 end;
112 (*******************************************************************
114 * Function : Load_TrueType_Collection
116 * Description :
118 * Input : face
120 * Output : True on success. False on failure
122 * Notes : A table directory doesn't own subttables. There is no
123 * constructor or destructor for it.
125 ******************************************************************)
127 function Load_TrueType_Collection( face : PFace ) : TError;
129 n : Int;
130 const
131 TTC_Tag = ( ord('t') shl 24 ) +
132 ( ord('t') shl 16 ) +
133 ( ord('c') shl 8 ) +
134 ( ord(' ') );
135 begin
136 Load_TrueType_Collection := Failure;
138 with face^.ttcHeader do
139 begin
141 if TT_Seek_File( 0 ) or
142 TT_Access_Frame( 12 ) then exit;
144 Tag := Get_ULong;
145 version := Get_Long;
146 dirCount := Get_Long;
148 TT_Forget_Frame;
150 if Tag <> TTC_Tag then
151 begin
152 Tag := 0;
153 version := 0;
154 dirCount := 0;
155 tableDirectory := nil;
157 error := TT_Err_File_Is_Not_Collection;
158 exit;
159 end;
161 if Alloc( tableDirectory, dirCount * sizeof(ULong) ) or
162 TT_Access_Frame( dirCount*4 ) then exit;
164 for n := 0 to dirCount-1 do
165 tableDirectory^[n] := Get_ULong;
167 TT_Forget_Frame;
168 end;
170 Load_TrueType_Collection := Success;
171 end;
173 (*******************************************************************
175 * Function : Load_TrueType_Directory
177 * Description :
179 * Input : face
181 * Output : True on success. False on failure
183 * Notes : A table directory doesn't own subttables. There is no
184 * constructor or destructor for it.
186 ******************************************************************)
188 function Load_TrueType_Directory( face : PFace;
189 faceIndex : Int ) : TError;
191 n : Int;
192 tableDir : TTableDir;
193 begin
194 Load_TrueType_Directory := Failure;
196 {$IFDEF DEBUG} Write('Directory '); {$ENDIF}
198 if Load_TrueType_Collection(face) then
199 begin
200 if error <> TT_Err_File_Is_Not_Collection then
201 exit;
203 (* The file isn't a collection, exit if index isn't 0 *)
204 if faceIndex <> 0 then
205 exit;
207 error := TT_Err_Ok;
209 (* Now skip to the beginning of the file *)
210 if TT_Seek_File(0) then
211 exit;
213 else
214 begin
215 (* file is a collection. Check the index *)
216 if ( faceIndex < 0 ) or
217 ( faceIndex >= face^.ttcHeader.dirCount ) then
218 begin
219 error := TT_Err_Bad_Argument;
220 exit;
221 end;
223 (* select a TT Font within the ttc file *)
224 if TT_Seek_File( face^.ttcHeader.tableDirectory^[faceIndex] ) then
225 exit;
226 end;
228 if TT_Access_Frame( 12 ) then
229 exit;
231 tableDir.version := GET_Long;
232 tableDir.numTables := GET_UShort;
234 tableDir.searchRange := GET_UShort;
235 tableDir.entrySelector := GET_UShort;
236 tableDir.rangeShift := GET_UShort;
238 {$IFDEF DEBUG} Writeln('Tables number : ', tableDir.numTables ); {$ENDIF}
240 TT_Forget_Frame;
242 (* Check that we have a 'sfnt' format there *)
243 if (tableDir.version <> $10000 ) and (* MS fonts *)
244 (tableDir.version <> $74727565) then (* Mac fonts *)
245 begin
246 {$IFDEF DEBUG} Writeln('Invalid font format'); {$ENDIF}
247 error := TT_Err_Invalid_File_Format;
248 exit;
249 end;
251 with face^ do
252 begin
254 numTables := tableDir.numTables;
256 if Alloc( dirTables, numTables * sizeof( TTableDirEntry ) ) or
257 TT_Access_Frame( 16 * numTables ) then exit;
259 for n := 0 to numTables-1 do with dirTables^[n] do
260 begin
261 Tag := GET_ULong;
262 Checksum := GET_ULong;
263 Offset := GET_Long;
264 Length := Get_Long;
265 end;
267 TT_Forget_Frame;
269 end;
271 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
273 Load_TrueType_Directory := Success;
274 end;
276 (*******************************************************************
278 * Function : Load_TrueType_MaxProfile
280 * Description :
282 * Input : face
284 * Output : True on success. False on failure
286 * Notes : A maximum profile is a static table that owns no
287 * subttable. It has then no constructor nor destructor
289 ******************************************************************)
291 function Load_TrueType_MaxProfile( face : PFace ) : TError;
293 table : int;
294 begin
296 Load_TrueType_MaxProfile := Failure;
298 {$IFDEF DEBUG} Write('MaxProfile '); {$ENDIF}
300 table := LookUp_Mandatory_Table( face, 'maxp');
301 if table < 0 then exit;
303 with face^ do
304 begin
306 if TT_Seek_File( dirTables^[table].Offset ) or
307 TT_Access_Frame( 32 ) then exit;
309 with MaxProfile do
310 begin
312 ULong(Version) := GET_ULong;
314 numGlyphs := GET_UShort;
315 maxPoints := GET_UShort;
316 maxContours := GET_UShort;
318 maxCompositePoints := GET_UShort;
319 maxCompositeContours := GET_UShort;
320 maxZones := GET_UShort;
321 maxTwilightPoints := GET_UShort;
322 maxStorage := GET_UShort;
323 maxFunctionDefs := GET_UShort;
324 maxINstructionDefs := GET_UShort;
325 maxStackElements := GET_UShort;
327 maxSizeOfInstructions := GET_UShort;
328 maxComponentElements := GET_UShort;
329 maxComponentDepth := GET_UShort;
330 end;
332 TT_Forget_Frame;
334 (* XXX : an adjustement that is necessary to load certain */
335 /* broken fonts like "Keystrokes MT" :-( */
336 /* */
337 /* We allocate 64 function entries by default when */
338 /* the maxFunctionDefs field is null. *)
340 (* otherwise, we increment this field by one, in order *)
341 (* to load some old Apple fonts.. *)
343 if maxProfile.maxFunctionDefs = 0 then
344 maxProfile.maxFunctionDefs := 64;
346 numGlyphs := MaxProfile.numGlyphs;
347 (* compute number of glyphs *)
349 maxPoints := MaxProfile.maxCompositePoints;
350 if (maxPoints < MaxProfile.maxPoints) then
351 maxPoints := MaxProfile.maxPoints;
352 (* compute max number of points *)
354 maxContours := MaxProfile.maxCompositeContours;
355 if maxContours < MaxProfile.maxContours then
356 maxContours := MaxProfile.maxContours;
357 (* compute max number of contours *)
359 maxComponents := MaxProfile.maxComponentElements +
360 MaxProfile.maxComponentDepth;
361 (* compute max number of components for glyph loading *)
363 (* XXX: some fonts have maxComponents set to 0; we will *)
364 (* then use 16 of them by default *)
365 if maxComponents = 0 then maxComponents := 16;
367 (* We also increase maxPoints and maxContours in order to support *)
368 (* some broken fonts *)
369 inc( maxPoints, 8 );
370 inc( maxContours, 4 );
371 end;
373 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
375 Load_TrueType_MaxProfile := Success;
376 end;
378 (*******************************************************************
380 * Function : Load_TrueType_Gasp
382 * Description :
384 * Input : face
386 ******************************************************************)
388 function Load_TrueType_Gasp( face : PFace ) : TError;
390 gRanges : PGaspRanges;
391 table, i : Int;
392 label
393 Fail;
394 begin
395 Load_TrueType_Gasp := Failure;
397 with face^.gasp do
398 begin
399 version := 0;
400 numRanges := 0;
401 gaspRanges := nil;
402 end;
404 table := Lookup_TrueType_Table( face, 'gasp' );
405 if ( table < 0 ) then
406 begin
407 Load_TrueType_Gasp := Success;
408 exit;
409 end;
411 if TT_Seek_File( face^.dirTables^[table].Offset ) or
412 TT_Access_Frame( 4 ) then exit;
414 with face^.gasp do
415 begin
416 version := Get_UShort;
417 numRanges := Get_UShort;
418 gaspRanges := nil;
419 end;
421 TT_Forget_Frame;
423 if Alloc( gRanges, face^.gasp.numRanges * sizeof(TGaspRange) ) or
424 TT_Access_Frame( face^.gasp.numRanges * 4 ) then
425 goto Fail;
427 face^.gasp.gaspRanges := gRanges;
429 for i := 0 to face^.gasp.numRanges-1 do
430 with gRanges^[i] do
431 begin
432 maxPPEM := Get_UShort;
433 gaspFlag := Get_UShort;
434 end;
436 TT_Forget_Frame;
438 Load_TrueType_Gasp := Success;
439 exit;
441 Fail:
442 Free( gRanges );
443 face^.gasp.numRanges := 0;
444 end;
447 (*******************************************************************
449 * Function : Load_TrueType_Header
451 * Description : Load the TrueType header table in the resident
452 * table
454 * Input : face current leading segment.
456 * Output : True on success. False on failure
458 * Notes : A font header is a static table that owns no
459 * subttable. It has then no constructor nor destructor
461 ******************************************************************)
463 function Load_TrueType_Header( face : PFace ) : TError;
465 i : int;
466 begin
467 Load_TrueType_Header := Failure;
469 {$IFDEF DEBUG} Write('Header '); {$ENDIF}
471 i := LookUp_Mandatory_Table(face, 'head');
472 if i <= 0 then exit;
474 with face^ do
475 begin
477 if TT_Seek_File( dirTables^[i].offset ) or
478 TT_Access_Frame( 54 ) then exit;
480 with FontHeader do
481 begin
483 ULong(Table_Version) := GET_ULong;
484 ULong(Font_Revision) := GET_ULong;
486 Checksum_Adjust := GET_Long;
487 Magic_Number := GET_Long;
489 Flags := GET_UShort;
490 Units_Per_EM := GET_UShort;
492 Created [0] := GET_Long; Created [1] := GET_Long;
493 Modified[0] := GET_Long; Modified[1] := GET_Long;
495 xMin := GET_Short;
496 yMin := GET_SHort;
497 xMax := GET_SHort;
498 yMax := GET_Short;
500 Mac_Style := GET_UShort;
501 Lowest_Rec_PPEM := GET_UShort;
503 Font_Direction := GET_Short;
504 Index_To_Loc_Format := GET_Short;
505 Glyph_Data_Format := GET_Short;
507 {$IFDEF DEBUG} Writeln('Units per EM : ',Units_Per_EM ); {$ENDIF}
509 end;
511 TT_Forget_Frame;
513 end;
515 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
517 Load_TrueType_Header := Success;
518 end;
520 (*******************************************************************
522 * Function : Load_TrueType_Metrics
524 * Description : Load TrueType metrics either from the "hmtx" or
525 * "vmtx" table.
527 * Input : face current resident leading segment
528 * vertical boolean. When set, try to load the vertical
529 * header.
531 * Output : True on success. False on failure
533 ******************************************************************)
535 function Load_TrueType_Metrics( face : PFace;
536 vertical : Boolean ) : TError;
538 table, n : int;
539 num_longs : int;
540 num_shorts : int;
541 num_shorts_checked : int;
542 temp : Short;
544 header : ^TT_Horizontal_Header;
546 shorts : ^PTableShortMetrics;
547 longs : ^PTableLongMetrics;
549 begin
550 Load_TrueType_Metrics := Failure;
552 {$IFDEF DEBUG}
553 if vertical then
554 Write('vmtx ')
555 else
556 Write('hmtx ');
557 {$ENDIF}
559 if vertical then
560 begin
562 table := LookUp_TrueType_Table( face, 'vmtx' );
563 if table < 0 then
564 begin
565 (* This is an optional table. Return silently if it *)
566 (* wasn't found. Note : some fonts have a vertical *)
567 (* header, but no 'vmtx'. E.g. : mingliu.ttf *)
569 face^.verticalHeader.number_Of_VMetrics := 0;
570 Load_TrueType_Metrics := Success;
571 exit;
572 end;
574 header := @TT_Horizontal_Header(face^.verticalHeader);
576 else
577 begin
578 table := LookUp_Mandatory_Table( face, 'hmtx' );
579 if table < 0 then
580 exit;
582 header := @face^.horizontalHeader;
583 end;
586 shorts := @PTableShortMetrics(header^.short_metrics);
587 longs := @PTableLongMetrics (header^.long_metrics );
589 num_longs := header^.number_Of_HMetrics;
590 num_shorts := face^.numGlyphs - num_longs;
592 num_shorts_checked := (face^.dirTables^[table].Length - num_longs*4) div 2;
594 if num_shorts < 0 then
595 begin
596 {$IFDEF DEBUG} Writeln('!! More metrics than glyphs !\n'); {$ENDIF}
597 if vertical then error := TT_Err_Invalid_Vert_Metrics
598 else error := TT_Err_Invalid_Horiz_Metrics;
599 exit;
600 end;
602 if Alloc( longs^, sizeof(TLongMetrics) * num_longs ) or
603 Alloc( shorts^, sizeof(TShortMetrics)* num_shorts ) or
605 TT_Seek_File( face^.dirTables^[table].Offset ) or
606 TT_Access_Frame( face^.dirTables^[table].Length ) then exit;
608 for n := 0 to num_longs-1 do with longs^^[n] do
609 begin
610 advance := GET_UShort;
611 bearing := GET_Short;
612 end;
614 (* do we have an inconsistent number of metric values ? *)
615 if num_shorts > num_shorts_checked then
616 begin
617 for n := 0 to num_shorts_checked-1 do
618 shorts^^[n] := GET_Short;
620 (* we fill up the missing left side bearings with the *)
621 (* last valid value. Since this will occur for buggy CJK *)
622 (* fonts usually, nothing serious will happen. *)
624 temp := shorts^^[num_shorts_checked-1];
626 for n := num_shorts_checked to num_shorts-1 do
627 shorts^^[n] := temp;
629 else
630 for n := 0 to num_shorts-1 do
631 shorts^^[n] := GET_Short;
633 TT_Forget_Frame;
635 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
637 Load_TrueType_Metrics := Success;
638 end;
641 (*******************************************************************
643 * Function : Load_TrueType_Metrics_Header
645 * Description :
647 * Input : face current resident leading segment
648 * vertical boolean. When set, try to load the vertical
649 * header.
651 * Output : True on success. False on failure
653 ******************************************************************)
655 function Load_TrueType_Metrics_Header( face : PFace;
656 vertical : Boolean ) : TError;
658 table : int;
659 header : ^TT_Horizontal_Header;
660 begin
661 Load_TrueType_Metrics_Header := Failure;
663 {$IFDEF DEBUG}
664 if vertical then
665 Write('Vertical Header ')
666 else
667 Write('Horizontal Header ');
668 {$ENDIF}
670 if vertical then
671 begin
672 face^.verticalInfo := False;
674 (* the vertical header is an optional table.. so return *)
675 (* silently if we don't find it *)
676 table := LookUp_TrueType_Table( face, 'vhea' );
677 if (table < 0) then
678 begin
679 Load_TrueType_Metrics_Header := Success;
680 exit;
681 end;
683 face^.verticalInfo := True;
684 header := @TT_Horizontal_Header(face^.verticalHeader);
686 else
687 begin
688 table := LookUp_Mandatory_Table( face, 'hhea');
689 if ( table < 0 ) then
690 exit;
691 header := @face^.horizontalHeader;
692 end;
694 with face^ do
695 begin
697 if TT_Seek_File( dirTables^[table].Offset ) or
698 TT_Access_Frame( 36 ) then
699 exit;
701 with header^ do
702 begin
704 Long(Version) := GET_ULong;
705 Ascender := GET_Short;
706 Descender := GET_Short;
707 Line_Gap := GET_Short;
709 advance_Width_Max := GET_UShort;
711 min_Left_Side_Bearing := GET_Short;
712 min_Right_Side_Bearing := GET_Short;
713 xMax_Extent := GET_Short;
714 caret_Slope_Rise := GET_Short;
715 caret_Slope_Run := GET_Short;
717 Reserved[0] := GET_Short; (* this is cared offset for vertical *)
719 Reserved[1] := GET_Short;
720 Reserved[2] := GET_Short;
721 Reserved[3] := GET_Short;
722 Reserved[4] := GET_Short;
724 metric_Data_Format := GET_Short;
725 number_Of_HMetrics := GET_UShort;
727 short_metrics := nil;
728 long_metrics := nil;
730 end;
732 TT_Forget_Frame;
734 end;
736 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
738 Load_TrueType_Metrics_Header := Load_TrueType_Metrics( face, vertical );
739 end;
741 (*******************************************************************
743 * Function : Load_TrueType_Locations
745 * Description : Loads the location table in resident table
747 * Input : face Current Resident Leading Segment
749 * Output : True on success. False on failure
751 * NOTES :
753 * The Font Header *must* be loaded in the leading segment
754 * before calling this function.
756 * This table is destroyed directly by the resident destructor.
758 ******************************************************************)
760 function Load_TrueType_Locations( face : PFace ): TError;
762 t, n : int;
763 LongOffsets : int;
764 begin
766 Load_TrueType_Locations := Failure;
768 {$IFDEF DEBUG} Write('Locations '); {$ENDIF}
770 with face^ do
771 begin
773 LongOffsets := fontHeader.Index_To_Loc_Format;
775 t := LookUp_Mandatory_Table( face, 'loca' );
776 if t < 0 then exit;
778 if TT_Seek_File( dirTables^[T].Offset ) then exit;
780 if LongOffsets <> 0 then
781 begin
783 numLocations := dirTables^[T].Length shr 2;
785 {$IFDEF DEBUG}
786 Writeln('Glyph locations # ( 32 bits offsets ) : ', numLocations );
787 {$ENDIF}
789 if Alloc( glyphLocations, sizeof(Long)*numLocations ) or
790 TT_Access_Frame( numLocations*4 ) then exit;
792 for n := 0 to numLocations-1 do
793 glyphLocations^[n] := GET_Long;
795 TT_Forget_Frame;
798 else
799 begin
800 numLocations := dirTables^[T].Length shr 1;
802 {$IFDEF DEBUG}
803 Writeln('Glyph locations # ( 16 bits offsets ) : ', numLocations );
804 {$ENDIF}
806 if Alloc( glyphLocations, sizeof(Long)*numLocations ) or
807 TT_Access_Frame( numLocations*2 ) then exit;
809 for n := 0 to numLocations-1 do
810 glyphLocations^[n] := Long(GET_UShort) * 2;
812 TT_Forget_Frame;
813 end;
815 end;
817 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
819 Load_TrueType_Locations := Success;
820 end;
823 (*******************************************************************
825 * Function : Load_TrueType_Names
827 * Description : Loads the name table into the face table
829 * Input : face
831 * Output : True on success. False on failure
833 * Notes : This attribute table is destroyed by the resident
834 * destructor.
836 ******************************************************************)
838 function Load_TrueType_Names( face : PFace ) : TError;
840 table, i : Int;
841 bytes : Long;
842 begin
843 Load_TrueType_Names := Failure;
845 table := Lookup_Mandatory_Table( face, 'name' );
846 if table < 0 then exit;
848 with face^.nameTable do
849 begin
850 (* Seek to the beginning of the table and check the frame access. *)
851 if TT_Seek_File( face^.dirTables^[table].Offset ) or
852 TT_Access_Frame( 6 ) then exit;
854 format := GET_UShort;
855 numNameRecords := GET_UShort;
856 storageOffset := GET_UShort;
858 TT_Forget_Frame;
860 if Alloc( names, numNameRecords*sizeof(TName_Record) ) or
861 TT_Access_Frame( numNameRecords*12 ) then
862 begin
863 numNameRecords := 0;
864 exit;
865 end;
867 (* Load the name records and determine how much storage is needed *)
868 (* to hold the strings themselves *)
870 bytes := 0;
871 for i := 0 to numNameRecords-1 do with names^[i] do
872 begin
873 platformID := GET_UShort;
874 encodingID := GET_UShort;
875 languageID := GET_UShort;
876 nameID := GET_UShort;
877 length := GET_UShort;
878 offset := GET_UShort;
880 (* this test takes care of 'holes' in the names tabls, as *)
881 (* reported by Erwin *)
882 if Offset + Length > bytes then
883 bytes := Offset + Length;
884 end;
886 TT_Forget_Frame;
888 storage := nil;
889 if bytes > 0 then
890 begin
891 if Alloc( storage, bytes ) then exit;
893 if TT_Read_At_File( face^.dirTables^[table].Offset + storageOffset,
894 storage^, bytes ) then
895 begin
896 Free(storage);
897 exit;
898 end;
899 end;
901 end;
903 Load_TrueType_Names := Success;
904 exit;
905 end;
907 (*******************************************************************
909 * Function : Load_TrueType_CVT
911 * Description :
913 * Input : face
915 * Output : True on success. False on failure
917 * Notes : This attribute table is destroyed by the resident
918 * destructor.
920 ******************************************************************)
922 function Load_TrueType_CVT( face : PFace ): TError;
924 t, n : Int;
925 begin
926 Load_TrueType_CVT := Failure;
928 {$IFDEF DEBUG} Write('CVT '); {$ENDIF}
930 (* the CVT table is optional *)
932 t := LookUp_TrueType_Table( face, 'cvt ');
933 if t < 0 then
934 begin
935 face^.cvt := nil;
936 face^.cvtSize := 0;
937 Load_TrueType_CVT := Success;
938 {$IFDEF DEBUG} writeln('none'); {$ENDIF}
939 exit;
940 end;
942 with face^ do
943 begin
945 cvtSize := dirTables^[t].Length div 2;
947 if Alloc( cvt, sizeof(Short)*cvtSize ) or
949 TT_Seek_File( dirTables^[t].Offset ) or
951 TT_Access_Frame( 2*cvtSize ) then exit;
953 for n := 0 to cvtSize-1 do
954 cvt^[n] := GET_Short;
956 TT_Forget_Frame;
957 end;
959 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
960 Load_TrueType_CVT := Success;
961 end;
964 (*******************************************************************
966 * Function : Load_TrueType_CMap
968 * Description :
970 * Input : face
972 * Output : True on success. False on failure
974 * Notes : The Cmap table directory is destroyed by the resident
975 * destructor. The Cmap subtables must be destroyed by
976 * Free_CMap_Table.
978 ******************************************************************)
980 function Load_TrueType_CMap( face : PFace ) : TError;
982 off, table_start : Longint;
983 n, limit, t : Int;
985 cmap_dir : TCMapDir;
986 entry : TCMapDirEntry;
987 cmap : PCMapTable;
988 label
989 Fail;
990 begin
992 Load_TrueType_CMap := Failure;
994 {$IFDEF DEBUG} Write('CMaps '); {$ENDIF}
996 t := LookUp_Mandatory_Table( face,'cmap' );
997 if t < 0 then exit;
999 with face^ do
1000 begin
1002 table_start := dirTables^[t].offset;
1004 if TT_Seek_File( dirTables^[t].Offset ) or
1005 TT_Access_Frame( 4 ) then exit;
1007 cmap_dir.tableVersionNumber := GET_UShort;
1008 cmap_dir.numCMaps := GET_UShort;
1010 TT_Forget_Frame;
1012 off := TT_File_Pos;
1014 (* save space in face data for cmap tables *)
1015 numCMaps := cmap_dir.numCMaps;
1016 if Alloc( cMaps, numCMaps * sizeof(TCMapTable) ) then exit;
1018 for n := 0 to numCMaps-1 do
1019 begin
1021 if TT_Seek_File ( off ) or
1022 TT_Access_Frame( 8 ) then exit;
1024 cmap := @cMaps^[n];
1026 entry.platformID := GET_UShort;
1027 entry.platformEncodingID := GET_UShort;
1028 entry.offset := GET_Long;
1030 cmap^.loaded := False;
1031 cmap^.platformID := entry.platformID;
1032 cmap^.platformEncodingID := entry.platformEncodingID;
1034 TT_Forget_Frame;
1036 off := TT_File_Pos;
1038 if TT_Seek_File ( table_start + entry.offset ) or
1039 TT_Access_Frame( 6 ) then exit;
1041 cmap^.format := Get_UShort;
1042 cmap^.length := Get_UShort;
1043 cmap^.version := Get_UShort;
1045 TT_Forget_Frame;
1047 cmap^.offset := TT_File_Pos;
1049 end; (* for n *)
1051 end; (* with face^ *)
1053 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1055 Load_TrueType_CMap := Success;
1056 exit;
1058 Fail:
1059 Free( face^.cMaps );
1060 Load_TrueType_CMap := Failure;
1061 end;
1065 procedure Free_CMap_Table( var cmap : TCMapTable );
1066 begin
1067 if cmap.cmap0 <> nil then
1068 with cmap do
1069 case format of
1071 0 : begin
1072 Free( cmap0^.glyphIdArray );
1073 Free( cmap0 );
1074 end;
1076 2 : begin
1077 Free( cmap2^.glyphIdArray );
1078 Free( cmap2^.subHeaders );
1079 Free( cmap2 );
1080 end;
1082 4 : begin
1083 Free( cmap4^.glyphIdArray );
1084 Free( cmap4^.segments );
1085 Free( cmap4 );
1086 end;
1088 6 : begin
1089 Free( cmap6^.glyphIdArray );
1090 Free( cmap6 );
1091 end;
1092 end;
1094 cmap.format := 0;
1095 cmap.length := 0;
1096 cmap.version := 0;
1097 end;
1100 (*******************************************************************
1102 * Function : Load_TrueType_Programs
1104 * Description : Load the Font and CVT programs in the resident
1105 * table
1107 * Input : face
1109 * Output : True on success. False on failure
1111 ******************************************************************)
1113 function Load_TrueType_Programs( face : PFace ) : TError;
1115 t : Int;
1116 begin
1118 Load_TrueType_Programs := Failure;
1120 {$IFDEF DEBUG} Write('Font program '); {$ENDIF}
1122 (* The font program is optional *)
1124 t := Lookup_TrueType_Table( face, 'fpgm' );
1126 if t < 0 then
1128 with face^ do
1129 begin
1130 fontProgram := nil;
1131 fontPgmSize := 0;
1133 {$IFDEF DEBUG} Writeln('none in file'); {$ENDIF}
1136 else
1138 with face^ do
1139 begin
1141 fontPgmSize := dirTables^[t].Length;
1143 if Alloc( fontProgram, fontPgmSize ) or
1144 TT_Read_At_File( dirTables^[t].offset,
1145 fontProgram^,
1146 fontPgmSize ) then exit;
1148 {$IFDEF DEBUG} Writeln('loaded, ',fontPgmSize,' bytes'); {$ENDIF}
1149 end;
1151 {$IFDEF DEBUG} Write('CVT program '); {$ENDIF}
1153 t := LookUp_trueType_Table( face, 'prep' );
1155 (* The CVT table is optional *)
1157 if t < 0 then
1159 with face^ do
1160 begin
1161 cvtProgram := nil;
1162 cvtPgmSize := 0;
1164 {$IFDEF DEBUG} Writeln('none in file'); {$ENDIF}
1167 else
1169 with face^ do
1170 begin
1172 cvtPgmSize := dirTables^[t].Length;
1174 if Alloc( cvtProgram, cvtPgmSize ) or
1175 TT_Read_At_File( dirTables^[t].offset,
1176 cvtProgram^,
1177 cvtPgmSize ) then exit;
1179 {$IFDEF DEBUG} Writeln('loaded, ',cvtPgmSize,' bytes'); {$ENDIF}
1180 end;
1182 Load_TrueType_Programs := Success;
1183 end;
1185 (*******************************************************************
1187 * Function : Load_TrueType_OS2
1189 * Description : Load the OS2 Table
1191 * Input : face
1193 * Output : True on success. False on failure
1195 ******************************************************************)
1197 function Load_TrueType_OS2( face : PFace ) : TError;
1199 table : Int;
1200 i : Int;
1201 begin
1202 Load_TrueType_OS2 := Failure;
1204 {$IFDEF DEBUG} Write('OS/2 table '); {$ENDIF}
1206 (* We now support Apple fonts who do not have an OS/2 table *)
1207 table := LookUp_Mandatory_Table( face, 'OS/2' );
1208 if table < 0 then begin
1209 face^.os2.version := $FFFF;
1210 Load_TrueType_OS2 := Success;
1211 error := TT_Err_Ok; (* clear error *)
1212 exit;
1213 end;
1215 if TT_Seek_File( face^.dirTables^[table].offset ) or
1216 TT_Access_Frame( 78 ) then exit;
1218 with face^.os2 do
1219 begin
1220 version := Get_UShort;
1221 xAvgCharWidth := Get_Short;
1222 usWeightClass := Get_UShort;
1223 usWidthClass := Get_UShort;
1224 fsType := Get_Short;
1225 ySubscriptXSize := Get_Short;
1226 ySubscriptYSize := Get_Short;
1227 ySubscriptXOffset := Get_Short;
1228 ySubscriptYOffset := Get_Short;
1229 ySuperscriptXSize := Get_Short;
1230 ySuperscriptYSize := Get_Short;
1231 ySuperscriptXOffset := Get_Short;
1232 ySuperscriptYOffset := Get_Short;
1233 yStrikeoutSize := Get_Short;
1234 yStrikeoutPosition := Get_Short;
1235 sFamilyClass := Get_Short;
1237 for i := 0 to 9 do panose[i] := Get_Byte;
1239 ulUnicodeRange1 := Get_ULong;
1240 ulUnicodeRange2 := Get_ULong;
1241 ulUnicodeRange3 := Get_ULong;
1242 ulUnicodeRange4 := Get_ULong;
1244 for i := 0 to 3 do achVendID[i] := Get_Byte;
1246 fsSelection := Get_UShort;
1247 usFirstCharIndex := Get_UShort;
1248 usLastCharIndex := Get_UShort;
1249 sTypoAscender := Get_UShort;
1250 sTypoDescender := Get_UShort;
1251 sTypoLineGap := Get_UShort;
1252 usWinAscent := Get_UShort;
1253 usWinDescent := Get_UShort;
1255 TT_Forget_Frame;
1257 if version >= $0001 then
1258 begin
1259 if TT_Access_Frame(8) then exit;
1261 ulCodePageRange1 := Get_ULong;
1262 ulCodePageRange2 := Get_ULong;
1264 TT_Forget_Frame;
1266 else
1267 begin
1268 ulCodePageRange1 := 0;
1269 ulCodePageRange2 := 0;
1270 end;
1272 end;
1274 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1276 Load_TrueType_OS2 := Success;
1277 end;
1279 (*******************************************************************
1281 * Function : Load_TrueType_Postscript
1283 * Description : Load the 'post' table
1285 * Input : face
1287 * Output : True on success. False on failure
1289 ******************************************************************)
1291 function Load_TrueType_Postscript( face : PFace ) : TError;
1293 table : Int;
1294 i : Int;
1295 begin
1296 Load_TrueType_Postscript := Failure;
1298 {$IFDEF DEBUG} Write('post table '); {$ENDIF}
1300 table := LookUp_TrueType_Table( face, 'post' );
1301 if table < 0 then exit;
1303 if TT_Seek_File( face^.dirTables^[table].offset ) or
1304 TT_Access_Frame(32) then exit;
1306 with face^.postscript do
1307 begin
1308 formatType := Get_ULong;
1309 italicAngle := Get_ULong;
1310 underlinePosition := Get_Short;
1311 underlineThickness := Get_Short;
1312 isFixedPitch := Get_ULong;
1313 minMemType42 := Get_ULong;
1314 maxMemType42 := Get_ULong;
1315 minMemType1 := Get_ULong;
1316 maxMemType1 := Get_ULong;
1317 end;
1319 TT_Forget_Frame;
1321 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1323 Load_trueType_Postscript := Success;
1324 end;
1326 (*******************************************************************
1328 * Function : Load_TrueType_HDMX
1330 * Description : Load the 'hdmx' tables
1332 * Input : face
1334 * Output : True on success. False on failure
1336 ******************************************************************)
1338 function Load_TrueType_Hdmx( face : PFace ) : TError;
1340 table, n : Int;
1341 num_glyphs : Int;
1343 version : UShort;
1344 num_rec : Short;
1345 recs : PHdmx_Records;
1346 rec_size : Long;
1347 rec : PHdmx_Record;
1348 label
1349 Fail;
1350 begin
1351 Load_TrueType_Hdmx := Failure;
1353 with face^.hdmx do
1354 begin
1355 version := 0;
1356 num_records := 0;
1357 records := nil;
1358 end;
1360 (* This table is optional *)
1362 table := LookUp_TrueType_Table( face, 'hdmx' );
1363 if table < 0 then
1364 begin
1365 Load_TrueType_Hdmx := Success;
1366 exit;
1367 end;
1369 if TT_Seek_File( face^.dirTables^[table].offset ) or
1370 TT_Access_Frame( 8 ) then exit;
1372 version := Get_UShort;
1373 num_rec := Get_Short;
1374 rec_size := Get_Long;
1376 TT_Forget_Frame;
1378 (* right now, we only recognize format 0 *)
1380 if version <> 0 then
1381 exit;
1383 if Alloc( face^.hdmx.records, sizeof(THdmx_Record)*num_rec ) then
1384 exit;
1386 face^.hdmx.num_records := num_rec;
1387 num_glyphs := face^.NumGlyphs;
1389 rec_size := rec_size - num_glyphs - 2;
1391 for n := 0 to num_rec-1 do
1392 begin
1393 rec := @face^.hdmx.records^[n];
1395 (* read record *)
1397 if TT_Access_Frame(2) then
1398 goto Fail;
1400 rec^.ppem := Get_Byte;
1401 rec^.max_width := Get_Byte;
1403 TT_Forget_Frame;
1405 if Alloc( rec^.widths, num_glyphs ) or
1406 TT_Read_File( rec^.widths^, num_glyphs ) then
1407 goto Fail;
1409 (* skip padding bytes *)
1411 if rec_size > 0 then
1412 if TT_Skip_File( rec_size ) then
1413 goto Fail;
1414 end;
1416 Load_TrueType_HDMX := Success;
1417 exit;
1419 Fail:
1420 for n := 0 to num_rec-1 do
1421 Free( face^.hdmx.records^[n].widths );
1423 Free( face^.hdmx.records );
1424 face^.hdmx.num_records := 0;
1425 end;
1428 (*******************************************************************
1430 * Function : Load_TrueType_Any
1432 * Description : Load any TrueType table in user memory
1434 * Input : face the font file's face object
1435 * tag the table
1437 * Output : True on success. False on failure
1439 ******************************************************************)
1441 function Load_TrueType_Any( face : PFace;
1442 tag : longint;
1443 offset : longint;
1444 var buffer;
1445 var length : longint ) : TError;
1447 stream : TT_Stream;
1448 found, i : integer;
1449 begin
1450 if tag <> 0 then
1451 begin
1452 found := -1;
1453 i := 0;
1454 while i < face^.numTables do
1455 if Longint(face^.dirTables^[i].tag) = tag then
1456 begin
1457 found := i;
1458 i := face^.numTables;
1460 else
1461 inc(i);
1463 if found < 0 then
1464 begin
1465 error := TT_Err_Table_Missing;
1466 Load_TrueType_Any := Failure;
1467 exit;
1468 end;
1470 inc( offset, face^.dirTables^[found].offset );
1472 (* if length = 0, the user requested the table's size *)
1473 if length = 0 then
1474 begin
1475 length := face^.dirTables^[found].length;
1476 Load_TrueType_Any := Success;
1477 exit;
1478 end;
1480 else
1481 (* if length = 0 and tag = 0, the user requested the font file's size *)
1482 if length = 0 then
1483 begin
1484 (* return length of font file *)
1485 length := TT_Stream_Size( face^.stream );
1486 Load_TrueType_Any := Success;
1487 exit;
1488 end;
1490 TT_Use_Stream( face^.stream, stream );
1491 Load_TrueType_Any := TT_Read_At_File( offset, buffer, length );
1492 TT_Done_Stream( face^.stream );
1493 end;
1495 end.