1 (*******************************************************************
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 ******************************************************************)
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
;
55 var length
: longint ) : TError
;
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
72 * Output : index of table if found, -1 otherwise.
74 ******************************************************************)
76 function LookUp_TrueType_Table( face
: PFace
;
77 aTag
: string ) : int
;
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
88 if face
^.dirTables
^[i
].Tag
= lTag
then
90 LookUp_TrueType_Table
:= i
;
95 (* couldn't find the table *)
96 LookUp_TrueType_Table
:= -1;
100 function LookUp_Mandatory_Table( face
: PFace
;
101 aTag
: string ) : int
;
105 table
:= LookUp_TrueType_Table( face
, aTag
);
107 error
:= TT_Err_Table_Missing
;
109 LookUp_Mandatory_Table
:= table
;
112 (*******************************************************************
114 * Function : Load_TrueType_Collection
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
;
131 TTC_Tag
= ( ord('t') shl 24 ) +
132 ( ord('t') shl 16 ) +
136 Load_TrueType_Collection
:= Failure
;
138 with face
^.ttcHeader
do
141 if TT_Seek_File( 0 ) or
142 TT_Access_Frame( 12 ) then exit
;
146 dirCount
:= Get_Long
;
150 if Tag
<> TTC_Tag
then
155 tableDirectory
:= nil;
157 error
:= TT_Err_File_Is_Not_Collection
;
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
;
170 Load_TrueType_Collection
:= Success
;
173 (*******************************************************************
175 * Function : Load_TrueType_Directory
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
;
192 tableDir
: TTableDir
;
194 Load_TrueType_Directory
:= Failure
;
196 {$IFDEF DEBUG} Write('Directory '); {$ENDIF}
198 if Load_TrueType_Collection(face
) then
200 if error
<> TT_Err_File_Is_Not_Collection
then
203 (* The file isn't a collection, exit if index isn't 0 *)
204 if faceIndex
<> 0 then
209 (* Now skip to the beginning of the file *)
210 if TT_Seek_File(0) then
215 (* file is a collection. Check the index *)
216 if ( faceIndex
< 0 ) or
217 ( faceIndex
>= face
^.ttcHeader
.dirCount
) then
219 error
:= TT_Err_Bad_Argument
;
223 (* select a TT Font within the ttc file *)
224 if TT_Seek_File( face
^.ttcHeader
.tableDirectory
^[faceIndex
] ) then
228 if TT_Access_Frame( 12 ) then
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}
242 (* Check that we have a 'sfnt' format there *)
243 if (tableDir
.version
<> $10000 ) and (* MS fonts *)
244 (tableDir
.version
<> $74727565) then (* Mac fonts *)
246 {$IFDEF DEBUG} Writeln('Invalid font format'); {$ENDIF}
247 error
:= TT_Err_Invalid_File_Format
;
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
262 Checksum
:= GET_ULong
;
271 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
273 Load_TrueType_Directory
:= Success
;
276 (*******************************************************************
278 * Function : Load_TrueType_MaxProfile
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
;
296 Load_TrueType_MaxProfile
:= Failure
;
298 {$IFDEF DEBUG} Write('MaxProfile '); {$ENDIF}
300 table
:= LookUp_Mandatory_Table( face
, 'maxp');
301 if table
< 0 then exit
;
306 if TT_Seek_File( dirTables
^[table
].Offset
) or
307 TT_Access_Frame( 32 ) then exit
;
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
;
334 (* XXX : an adjustement that is necessary to load certain */
335 /* broken fonts like "Keystrokes MT" :-( */
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 *)
370 inc( maxContours
, 4 );
373 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
375 Load_TrueType_MaxProfile
:= Success
;
378 (*******************************************************************
380 * Function : Load_TrueType_Gasp
386 ******************************************************************)
388 function Load_TrueType_Gasp( face
: PFace
) : TError
;
390 gRanges
: PGaspRanges
;
395 Load_TrueType_Gasp
:= Failure
;
404 table
:= Lookup_TrueType_Table( face
, 'gasp' );
405 if ( table
< 0 ) then
407 Load_TrueType_Gasp
:= Success
;
411 if TT_Seek_File( face
^.dirTables
^[table
].Offset
) or
412 TT_Access_Frame( 4 ) then exit
;
416 version
:= Get_UShort
;
417 numRanges
:= Get_UShort
;
423 if Alloc( gRanges
, face
^.gasp
.numRanges
* sizeof(TGaspRange
) ) or
424 TT_Access_Frame( face
^.gasp
.numRanges
* 4 ) then
427 face
^.gasp
.gaspRanges
:= gRanges
;
429 for i
:= 0 to face
^.gasp
.numRanges
-1 do
432 maxPPEM
:= Get_UShort
;
433 gaspFlag
:= Get_UShort
;
438 Load_TrueType_Gasp
:= Success
;
443 face
^.gasp
.numRanges
:= 0;
447 (*******************************************************************
449 * Function : Load_TrueType_Header
451 * Description : Load the TrueType header table in the resident
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
;
467 Load_TrueType_Header
:= Failure
;
469 {$IFDEF DEBUG} Write('Header '); {$ENDIF}
471 i
:= LookUp_Mandatory_Table(face
, 'head');
477 if TT_Seek_File( dirTables
^[i
].offset
) or
478 TT_Access_Frame( 54 ) then exit
;
483 ULong(Table_Version
) := GET_ULong
;
484 ULong(Font_Revision
) := GET_ULong
;
486 Checksum_Adjust
:= GET_Long
;
487 Magic_Number
:= GET_Long
;
490 Units_Per_EM
:= GET_UShort
;
492 Created
[0] := GET_Long
; Created
[1] := GET_Long
;
493 Modified
[0] := GET_Long
; Modified
[1] := GET_Long
;
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}
515 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
517 Load_TrueType_Header
:= Success
;
520 (*******************************************************************
522 * Function : Load_TrueType_Metrics
524 * Description : Load TrueType metrics either from the "hmtx" or
527 * Input : face current resident leading segment
528 * vertical boolean. When set, try to load the vertical
531 * Output : True on success. False on failure
533 ******************************************************************)
535 function Load_TrueType_Metrics( face
: PFace
;
536 vertical
: Boolean ) : TError
;
541 num_shorts_checked
: int
;
544 header
: ^TT_Horizontal_Header
;
546 shorts
: ^PTableShortMetrics
;
547 longs
: ^PTableLongMetrics
;
550 Load_TrueType_Metrics
:= Failure
;
562 table
:= LookUp_TrueType_Table( face
, 'vmtx' );
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
;
574 header
:= @TT_Horizontal_Header(face
^.verticalHeader
);
578 table
:= LookUp_Mandatory_Table( face
, 'hmtx' );
582 header
:= @face
^.horizontalHeader
;
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
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
;
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
610 advance
:= GET_UShort
;
611 bearing
:= GET_Short
;
614 (* do we have an inconsistent number of metric values ? *)
615 if num_shorts
> num_shorts_checked
then
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
630 for n
:= 0 to num_shorts
-1 do
631 shorts
^^[n
] := GET_Short
;
635 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
637 Load_TrueType_Metrics
:= Success
;
641 (*******************************************************************
643 * Function : Load_TrueType_Metrics_Header
647 * Input : face current resident leading segment
648 * vertical boolean. When set, try to load the vertical
651 * Output : True on success. False on failure
653 ******************************************************************)
655 function Load_TrueType_Metrics_Header( face
: PFace
;
656 vertical
: Boolean ) : TError
;
659 header
: ^TT_Horizontal_Header
;
661 Load_TrueType_Metrics_Header
:= Failure
;
665 Write('Vertical Header ')
667 Write('Horizontal Header ');
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' );
679 Load_TrueType_Metrics_Header
:= Success
;
683 face
^.verticalInfo
:= True;
684 header
:= @TT_Horizontal_Header(face
^.verticalHeader
);
688 table
:= LookUp_Mandatory_Table( face
, 'hhea');
689 if ( table
< 0 ) then
691 header
:= @face
^.horizontalHeader
;
697 if TT_Seek_File( dirTables
^[table
].Offset
) or
698 TT_Access_Frame( 36 ) then
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;
736 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
738 Load_TrueType_Metrics_Header
:= Load_TrueType_Metrics( face
, vertical
);
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
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
;
766 Load_TrueType_Locations
:= Failure
;
768 {$IFDEF DEBUG} Write('Locations '); {$ENDIF}
773 LongOffsets
:= fontHeader
.Index_To_Loc_Format
;
775 t
:= LookUp_Mandatory_Table( face
, 'loca' );
778 if TT_Seek_File( dirTables
^[T
].Offset
) then exit
;
780 if LongOffsets
<> 0 then
783 numLocations
:= dirTables
^[T
].Length
shr 2;
786 Writeln('Glyph locations # ( 32 bits offsets ) : ', numLocations
);
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
;
800 numLocations
:= dirTables
^[T
].Length
shr 1;
803 Writeln('Glyph locations # ( 16 bits offsets ) : ', numLocations
);
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;
817 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
819 Load_TrueType_Locations
:= Success
;
823 (*******************************************************************
825 * Function : Load_TrueType_Names
827 * Description : Loads the name table into the face table
831 * Output : True on success. False on failure
833 * Notes : This attribute table is destroyed by the resident
836 ******************************************************************)
838 function Load_TrueType_Names( face
: PFace
) : TError
;
843 Load_TrueType_Names
:= Failure
;
845 table
:= Lookup_Mandatory_Table( face
, 'name' );
846 if table
< 0 then exit
;
848 with face
^.nameTable
do
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
;
860 if Alloc( names
, numNameRecords
*sizeof(TName_Record
) ) or
861 TT_Access_Frame( numNameRecords
*12 ) then
867 (* Load the name records and determine how much storage is needed *)
868 (* to hold the strings themselves *)
871 for i
:= 0 to numNameRecords
-1 do with names
^[i
] do
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
;
891 if Alloc( storage
, bytes
) then exit
;
893 if TT_Read_At_File( face
^.dirTables
^[table
].Offset
+ storageOffset
,
894 storage
^, bytes
) then
903 Load_TrueType_Names
:= Success
;
907 (*******************************************************************
909 * Function : Load_TrueType_CVT
915 * Output : True on success. False on failure
917 * Notes : This attribute table is destroyed by the resident
920 ******************************************************************)
922 function Load_TrueType_CVT( face
: PFace
): TError
;
926 Load_TrueType_CVT
:= Failure
;
928 {$IFDEF DEBUG} Write('CVT '); {$ENDIF}
930 (* the CVT table is optional *)
932 t
:= LookUp_TrueType_Table( face
, 'cvt ');
937 Load_TrueType_CVT
:= Success
;
938 {$IFDEF DEBUG} writeln('none'); {$ENDIF}
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
;
959 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
960 Load_TrueType_CVT
:= Success
;
964 (*******************************************************************
966 * Function : Load_TrueType_CMap
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
978 ******************************************************************)
980 function Load_TrueType_CMap( face
: PFace
) : TError
;
982 off
, table_start
: Longint;
986 entry
: TCMapDirEntry
;
992 Load_TrueType_CMap
:= Failure
;
994 {$IFDEF DEBUG} Write('CMaps '); {$ENDIF}
996 t
:= LookUp_Mandatory_Table( face
,'cmap' );
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
;
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
1021 if TT_Seek_File ( off
) or
1022 TT_Access_Frame( 8 ) then exit
;
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
;
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
;
1047 cmap
^.offset
:= TT_File_Pos
;
1051 end; (* with face^ *)
1053 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1055 Load_TrueType_CMap
:= Success
;
1059 Free( face
^.cMaps
);
1060 Load_TrueType_CMap
:= Failure
;
1065 procedure Free_CMap_Table( var cmap : TCMapTable );
1067 if cmap.cmap0 <> nil then
1072 Free( cmap0^.glyphIdArray );
1077 Free( cmap2^.glyphIdArray );
1078 Free( cmap2^.subHeaders );
1083 Free( cmap4^.glyphIdArray );
1084 Free( cmap4^.segments );
1089 Free( cmap6^.glyphIdArray );
1100 (*******************************************************************
1102 * Function : Load_TrueType_Programs
1104 * Description : Load the Font and CVT programs in the resident
1109 * Output : True on success. False on failure
1111 ******************************************************************)
1113 function Load_TrueType_Programs( face
: PFace
) : TError
;
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' );
1133 {$IFDEF DEBUG} Writeln('none in file'); {$ENDIF}
1141 fontPgmSize
:= dirTables
^[t
].Length
;
1143 if Alloc( fontProgram
, fontPgmSize
) or
1144 TT_Read_At_File( dirTables
^[t
].offset
,
1146 fontPgmSize
) then exit
;
1148 {$IFDEF DEBUG} Writeln('loaded, ',fontPgmSize
,' bytes'); {$ENDIF}
1151 {$IFDEF DEBUG} Write('CVT program '); {$ENDIF}
1153 t
:= LookUp_trueType_Table( face
, 'prep' );
1155 (* The CVT table is optional *)
1164 {$IFDEF DEBUG} Writeln('none in file'); {$ENDIF}
1172 cvtPgmSize
:= dirTables
^[t
].Length
;
1174 if Alloc( cvtProgram
, cvtPgmSize
) or
1175 TT_Read_At_File( dirTables
^[t
].offset
,
1177 cvtPgmSize
) then exit
;
1179 {$IFDEF DEBUG} Writeln('loaded, ',cvtPgmSize
,' bytes'); {$ENDIF}
1182 Load_TrueType_Programs
:= Success
;
1185 (*******************************************************************
1187 * Function : Load_TrueType_OS2
1189 * Description : Load the OS2 Table
1193 * Output : True on success. False on failure
1195 ******************************************************************)
1197 function Load_TrueType_OS2( face
: PFace
) : TError
;
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 *)
1215 if TT_Seek_File( face
^.dirTables
^[table
].offset
) or
1216 TT_Access_Frame( 78 ) then exit
;
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
;
1257 if version
>= $0001 then
1259 if TT_Access_Frame(8) then exit
;
1261 ulCodePageRange1
:= Get_ULong
;
1262 ulCodePageRange2
:= Get_ULong
;
1268 ulCodePageRange1
:= 0;
1269 ulCodePageRange2
:= 0;
1274 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1276 Load_TrueType_OS2
:= Success
;
1279 (*******************************************************************
1281 * Function : Load_TrueType_Postscript
1283 * Description : Load the 'post' table
1287 * Output : True on success. False on failure
1289 ******************************************************************)
1291 function Load_TrueType_Postscript( face
: PFace
) : TError
;
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
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
;
1321 {$IFDEF DEBUG} Writeln('loaded'); {$ENDIF}
1323 Load_trueType_Postscript
:= Success
;
1326 (*******************************************************************
1328 * Function : Load_TrueType_HDMX
1330 * Description : Load the 'hdmx' tables
1334 * Output : True on success. False on failure
1336 ******************************************************************)
1338 function Load_TrueType_Hdmx( face
: PFace
) : TError
;
1345 recs
: PHdmx_Records
;
1351 Load_TrueType_Hdmx
:= Failure
;
1360 (* This table is optional *)
1362 table
:= LookUp_TrueType_Table( face
, 'hdmx' );
1365 Load_TrueType_Hdmx
:= Success
;
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
;
1378 (* right now, we only recognize format 0 *)
1380 if version
<> 0 then
1383 if Alloc( face
^.hdmx
.records
, sizeof(THdmx_Record
)*num_rec
) then
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
1393 rec
:= @face
^.hdmx
.records
^[n
];
1397 if TT_Access_Frame(2) then
1400 rec
^.ppem
:= Get_Byte
;
1401 rec
^.max_width
:= Get_Byte
;
1405 if Alloc( rec
^.widths
, num_glyphs
) or
1406 TT_Read_File( rec
^.widths
^, num_glyphs
) then
1409 (* skip padding bytes *)
1411 if rec_size
> 0 then
1412 if TT_Skip_File( rec_size
) then
1416 Load_TrueType_HDMX
:= Success
;
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;
1428 (*******************************************************************
1430 * Function : Load_TrueType_Any
1432 * Description : Load any TrueType table in user memory
1434 * Input : face the font file's face object
1437 * Output : True on success. False on failure
1439 ******************************************************************)
1441 function Load_TrueType_Any( face
: PFace
;
1445 var length
: longint ) : TError
;
1454 while i
< face
^.numTables
do
1455 if Longint(face
^.dirTables
^[i
].tag
) = tag
then
1458 i
:= face
^.numTables
;
1465 error
:= TT_Err_Table_Missing
;
1466 Load_TrueType_Any
:= Failure
;
1470 inc( offset
, face
^.dirTables
^[found
].offset
);
1472 (* if length = 0, the user requested the table's size *)
1475 length
:= face
^.dirTables
^[found
].length
;
1476 Load_TrueType_Any
:= Success
;
1481 (* if length = 0 and tag = 0, the user requested the font file's size *)
1484 (* return length of font file *)
1485 length
:= TT_Stream_Size( face
^.stream
);
1486 Load_TrueType_Any
:= Success
;
1490 TT_Use_Stream( face
^.stream
, stream
);
1491 Load_TrueType_Any
:= TT_Read_At_File( offset
, buffer
, length
);
1492 TT_Done_Stream( face
^.stream
);