unit TTObjs;
interface
uses FreeType,
TTTypes,
TTError,
TTCache,
TTTables,
TTCMap;
type
PGraphicsState = ^TGraphicsState;
TGraphicsState = record
rp0,
rp1,
rp2 : int;
dualVector,
projVector,
freeVector : TT_UnitVector;
loop : longint;
minimum_distance : TT_F26dot6;
round_state : int;
auto_flip : boolean;
control_value_cutin : TT_F26dot6;
single_width_cutin : TT_F26dot6;
single_width_value : TT_F26dot6;
delta_base : int;
delta_shift : int;
instruct_control : byte;
scan_control : Boolean;
scan_type : Int;
gep0,
gep1,
gep2 : int;
end;
const
Default_GraphicsState : TGraphicsState
= (
rp0 : 0;
rp1 : 0;
rp2 : 0;
dualVector : ( x:$4000; y:0 );
projVector : ( x:$4000; y:0 );
freeVector : ( x:$4000; y:0 );
loop : 1;
minimum_distance : 64;
round_state : 1;
auto_flip : True;
control_value_cutin : 4*17;
single_width_cutin : 0;
single_width_value : 0;
delta_Base : 9;
delta_Shift : 3;
instruct_control : 0;
scan_control : True;
scan_type : 0;
gep0 : 1;
gep1 : 1;
gep2 : 1
);
const
MaxCodeRanges = 3;
TT_CodeRange_Font = 1;
TT_CodeRange_Cvt = 2;
TT_CodeRange_Glyph = 3;
CvtFlag_None = 0;
CvtFlag_X = 1;
CvtFlag_Y = 2;
CvtFlag_Both = 3;
type
TCodeRange = record
Base : PByte;
Size : Int;
end;
PCodeRange = ^TCodeRange;
TCodeRangeTable = array[1..MaxCodeRanges] of TCodeRange;
PDefRecord = ^TDefRecord;
TDefRecord = record
Range : Int;
Start : Int;
Opc : Byte;
Active : boolean;
end;
PDefArray = ^TDefArray;
TDefArray = array[0..99] of TDefRecord;
TCallRecord = record
Caller_Range : Int;
Caller_IP : Int;
Cur_Count : Int;
Cur_Restart : Int;
end;
TCallStack = array[0..99] of TCallRecord;
PCallStack = ^TCallStack;
PGlyph_Zone = ^TGlyph_Zone;
TGlyph_Zone = record
n_points : Int;
n_contours : Int;
org : TT_Points;
cur : TT_Points;
flags : TT_PTouchTable;
conEnds : PUShort;
end;
TRound_Function = function( distance, compensation : TT_F26dot6 )
: TT_F26dot6;
TMove_Function = procedure( zone : PGlyph_Zone;
point : Int;
distance : TT_F26dot6 );
TProject_Function = function( var P1, P2 : TT_Vector ) : TT_F26dot6;
TFunc_Get_CVT = function ( index : Int ) : TT_F26Dot6;
TFunc_Set_CVT = procedure( index : Int; value : TT_F26Dot6 );
PGlyph_Transform = ^TGlyph_Transform;
TGlyph_Transform = record
xx, xy : TT_Fixed;
yx, yy : TT_Fixed;
ox, oy : TT_F26Dot6;
end;
PSubglyph_Record = ^TSubglyph_Record;
TSubglyph_Record = record
index : Int;
is_scaled : boolean;
is_hinted : boolean;
preserve_pps : boolean;
bbox : TT_BBox;
zone : TGlyph_Zone;
arg1, arg2 : Int;
element_flag : Int;
transform : TGlyph_Transform;
file_offset : Long;
pp1, pp2 : TT_Vector;
advanceWidth : Int;
leftBearing : Int;
end;
TSubglyph_Stack = array[0..10] of TSubglyph_Record;
PSubglyph_Stack = ^TSubglyph_Stack;
TIns_Metrics = record
pointsize : TT_F26Dot6;
x_resolution : Int;
y_resolution : Int;
x_ppem : Int;
y_ppem : Int;
x_scale1 : Long;
x_scale2 : Long;
y_scale1 : Long;
y_scale2 : Long;
x_ratio : Long;
y_ratio : Long;
scale1 : Long;
scale2 : Long;
ppem : Int;
ratio : Long;
compensations : array[0..3] of TT_F26Dot6;
rotated : Boolean;
stretched : Boolean;
end;
PFace = ^TFace;
PInstance = ^TInstance;
PExec_Context = ^TExec_Context;
TFace = record
stream : TT_Stream;
ttcHeader : TTTCHeader;
maxProfile : TMaxProfile;
fontHeader : TT_Header;
horizontalHeader : TT_Horizontal_Header;
verticalInfo : Boolean;
verticalHeader : TT_Vertical_Header;
os2 : TT_OS2;
postscript : TT_Postscript;
hdmx : THdmx;
nameTable : TName_Table;
numTables : Int;
dirTables : PTableDirEntries;
numCMaps : Int;
cMaps : PCMapTables;
numLocations : Int;
glyphLocations : PStorage;
fontPgmSize : Int;
fontProgram : PByte;
cvtPgmSize : Int;
cvtProgram : PByte;
cvtSize : Int;
cvt : PShort;
gasp : TGasp;
numGlyphs : Int;
maxPoints : Int;
maxContours : Int;
maxComponents : Int;
instances : TCache;
glyphs : TCache;
extension : Pointer;
generic : Pointer;
end;
TInstance = record
owner : PFace;
valid : Boolean;
metrics : TIns_Metrics;
numFDefs : Int;
maxFDefs : Int;
FDefs : PDefArray;
numIDefs : Int;
maxIDefs : Int;
IDefs : PDefArray;
maxFunc : Int;
maxIns : Int;
codeRangeTable : TCodeRangeTable;
GS : TGraphicsState;
storeSize : Int;
storage : PStorage;
cvtSize : Int;
cvt : PLong;
twilight : TGlyph_Zone;
debug : Boolean;
context : PExec_Context;
generic : Pointer;
end;
TExec_Context = record
face : PFace;
instance : PInstance;
error : Int;
stackSize : Int;
top : Int;
stack : PStorage;
args : Int;
new_top : Int;
zp0,
zp1,
zp2,
twilight,
pts : TGlyph_Zone;
GS : TGraphicsState;
curRange : Int;
code : PByte;
IP : Int;
codeSize : Int;
opcode : Byte;
length : Int;
step_ins : boolean;
loadSize : Int;
loadStack : PSubglyph_Stack;
glyphIns : PByte;
glyphSize : Int;
callTop : Int;
callSize : Int;
callStack : PCallStack;
period,
phase,
threshold : TT_F26dot6;
maxPoints : Int;
maxContours : Int;
numFDefs : Int;
maxFDefs : Int;
FDefs : PDefArray;
numIDefs : Int;
maxIDefs : Int;
IDefs : PDefArray;
maxFunc : Int;
maxIns : Int;
codeRangeTable : TCodeRangeTable;
storeSize : Int;
storage : PStorage;
metrics : TIns_Metrics;
cur_ppem : Int;
scale1 : Long;
scale2 : Long;
cached_metrics : Boolean;
Instruction_Trap : Boolean;
is_composite : Boolean;
cvtSize : Int;
cvt : PLong;
F_dot_P : Long;
func_round : TRound_Function;
func_project : TProject_Function;
func_dualproj : TProject_Function;
func_freeProj : TProject_Function;
func_move : TMove_Function;
func_read_cvt : TFunc_Get_CVT;
func_write_cvt : TFunc_Set_CVT;
func_move_cvt : TFunc_Set_CVT;
end;
PGlyph = ^TGlyph;
TGlyph = record
face : PFace;
metrics : TT_Big_Glyph_Metrics;
outline : TT_Outline;
computed_width : Int;
precalc_width : Int;
is_composite : Boolean;
end;
PFont_Input = ^TFont_Input;
TFont_Input = record
stream : TT_Stream;
fontIndex : Int;
end;
function Goto_CodeRange( exec : PExec_Context;
range : Int;
IP : Int ) : TError;
function Get_CodeRange( exec : PExec_Context;
range : Int ) : PCodeRange;
function Set_CodeRange( exec : PExec_Context;
range : Int;
base : Pointer;
length : Int ) : TError;
function Clear_CodeRange( exec : PExec_Context;
range : Int ) : TError;
function New_Context( instance : PInstance ) : PExec_Context;
procedure Done_Context( exec : PExec_Context );
procedure Context_Load( exec : PExec_Context;
ins : PInstance );
procedure Context_Save( exec : PExec_Context;
ins : PInstance );
function Context_Run( exec : PExec_Context;
debug : Boolean ) : TError;
function Instance_Init( ins : PInstance ) : TError;
function Instance_Reset( ins : PInstance;
debug : boolean ) : TError;
function Scale_X( var metrics : TIns_Metrics; x : TT_Pos ) : TT_Pos;
function Scale_Y( var metrics : TIns_Metrics; y : TT_Pos ) : TT_Pos;
function TTObjs_Init : TError;
procedure TTObjs_Done;
var
face_cache : TCache;
exec_cache : TCache;
implementation
uses TTMemory, TTFile, TTCalc, TTLoad, TTInterp;
function Face_Create( _face : Pointer;
_input : Pointer ) : TError; far; forward;
function Face_Destroy( _face : Pointer ) : TError; far; forward;
function Context_Create( _context : Pointer;
_face : Pointer ) : TError; far; forward;
function Context_Destroy( exec : Pointer ) : TError; far; forward;
function Instance_Create( _ins : Pointer;
_face : Pointer ) : TError; far; forward;
function Instance_Destroy( instance : Pointer ) : TError; far; forward;
function Glyph_Create( _glyph : Pointer;
_face : Pointer ) : TError; far; forward;
function Glyph_Destroy( _glyph : Pointer ) : TError; far; forward;
const
objs_face_class : TCache_Class
= (object_size: sizeof(TFace);
idle_limit : -1;
init : Face_Create;
done : Face_Destroy );
objs_exec_class : TCache_Class
= (object_size: sizeof(TExec_Context);
idle_limit : 1;
init : Context_Create;
done : Context_Destroy );
objs_instance_class : TCache_Class
= (object_size: sizeof(TInstance);
idle_limit : -1;
init : Instance_Create;
done : Instance_Destroy );
objs_glyph_class : TCache_Class
= (object_size: sizeof(TGlyph);
idle_limit : -1;
init : Glyph_Create;
done : Glyph_Destroy );
function New_Context( instance : PInstance ) : PExec_Context;
var
exec : PExec_Context;
begin
if instance = nil then
exec := nil
else
Cache_New( exec_cache, Pointer(exec), instance^.owner );
New_Context := exec;
end;
procedure Done_Context( exec : PExec_Context );
begin
if exec <> nil then
Cache_Done( exec_cache, Pointer(exec) );
end;
function New_Instance( face : PFace ) : PInstance;
var
ins : PInstance;
begin
if face = nil then
ins := nil
else
Cache_New( face^.instances, Pointer(ins), face );
New_Instance := ins;
end;
procedure Done_Instance( instance : PInstance );
begin
if instance <> nil then
Cache_Done( instance^.owner^.instances, Pointer(instance) );
end;
function Goto_CodeRange( exec : PExec_Context;
range : Int;
IP : Int ) : TError;
begin
Goto_CodeRange := Failure;
if (range < 1) or (range > 3) then
begin
error := TT_Err_Bad_Argument;
exit;
end;
with exec^.codeRangeTable[range] do
begin
if base = nil then
begin
error := TT_Err_Invalid_CodeRange;
exit;
end;
if IP > size then
begin
error := TT_Err_Code_Overflow;
exit;
end;
exec^.code := base;
exec^.codeSize := size;
exec^.IP := IP;
exec^.currange := range;
end;
Goto_CodeRange := Success;
end;
function Get_CodeRange( exec : PExec_Context;
range : Int ) : PCodeRange;
begin
if (range < 1) or (range > 3) then
Get_CodeRange := nil
else
Get_CodeRange := @exec^.codeRangeTable[range];
end;
function Set_CodeRange( exec : PExec_Context;
range : Int;
base : Pointer;
length : Int ) : TError;
begin
Set_CodeRange := Failure;
if (range < 1) or (range > 3) then
begin
error := TT_Err_Invalid_CodeRange;
exit;
end;
exec^.codeRangeTable[range].base := base;
exec^.codeRangeTable[range].size := length;
Set_CodeRange := Success;
end;
function Clear_CodeRange( exec : PExec_Context;
range : Int ) : TError;
begin
Clear_CodeRange := Failure;
if (range < 1) or (range > 3) then
begin
error := TT_Err_Invalid_CodeRange;
exit;
end;
exec^.codeRangeTable[range].base := nil;
exec^.codeRangeTable[range].size := 0;
Clear_CodeRange := Success;
end;
function Context_Destroy( exec : Pointer ) : TError;
begin
Context_Destroy := Success;
if exec = nil then exit;
with PExec_Context(exec)^ do
begin
Free( pts.conEnds );
pts.n_contours := 0;
Free( pts.cur );
Free( pts.org );
Free( pts.flags );
pts.n_points := 0;
Free( stack );
stackSize := 0;
Free( callStack );
callSize := 0;
callTop := 0;
Free( loadStack );
Free( glyphIns );
glyphSize := 0;
instance := nil;
face := nil;
end;
end;
function Context_Create( _context : Pointer;
_face : Pointer ) : TError;
var
n_points : Int;
n_twilight : Int;
exec : PExec_Context;
label
Fail_Memory;
begin
Context_Create := Failure;
exec := PExec_Context(_context);
exec^.face := PFace(_face);
with exec^ do
begin
callSize := 32;
loadSize := face^.maxComponents + 1;
storeSize := face^.MaxProfile.maxStorage;
stackSize := face^.MaxProfile.maxStackElements + 32;
n_points := face^.maxPoints + 2;
if Alloc( glyphIns, face^.MaxProfile.maxSizeOfInstructions ) or
Alloc( callStack, callSize*sizeof(TCallRecord) ) or
Alloc( stack, stackSize*sizeof(Long) ) then
goto Fail_Memory;
maxPoints := 0;
maxContours := 0;
loadSize := 0;
loadStack := nil;
pts.n_points := 0;
pts.n_contours := 0;
instance := nil;
end;
Context_Create := Success;
exit;
Fail_Memory:
Context_Destroy(_context);
error := TT_Err_Out_Of_Memory;
exit;
end;
function Context_Run( exec : PExec_Context;
debug : Boolean ) : TError;
begin
Context_Run := Failure;
if Goto_CodeRange( exec, TT_CodeRange_Glyph, 0 ) then
exit;
with exec^ do
begin
top := 0;
callTop := 0;
zp0 := pts;
zp1 := pts;
zp2 := pts;
GS.gep0 := 1;
GS.gep1 := 1;
GS.gep2 := 1;
GS.projVector.x := $4000;
GS.projVector.y := $0000;
GS.freeVector := GS.projVector;
GS.dualVector := GS.projVector;
GS.round_state := 1;
GS.loop := 1;
end;
if not debug and Run_Ins( @exec^ ) then
begin
error := exec^.error;
exit;
end;
Context_Run := Success;
end;
procedure Context_Load( exec : PExec_Context;
ins : PInstance );
procedure Update_Max( var size : Int;
mult : Int;
var buff;
new_max : Int );
begin
if size*mult < new_max then
begin
Free(buff);
Alloc( buff, new_max*mult );
size := new_max;
end;
end;
procedure Update_Points( max_points : Int;
max_contours : Int;
exec : PExec_Context );
begin
if exec^.maxPoints < max_points then
begin
Free( exec^.pts.org );
Free( exec^.pts.cur );
Free( exec^.pts.flags );
Alloc( exec^.pts.org, 2*sizeof(TT_F26dot6)*max_points );
Alloc( exec^.pts.cur, 2*sizeof(TT_F26dot6)*max_points );
Alloc( exec^.pts.flags, sizeof(Byte) *max_points );
exec^.maxPoints := max_points;
end;
if exec^.maxContours < max_contours then
begin
Free( exec^.pts.conEnds );
Alloc( exec^.pts.conEnds, sizeof(Short)*max_contours );
exec^.maxContours := max_contours;
end;
end;
begin
with exec^ do
begin
instance := ins;
face := ins^.owner;
numFDefs := ins^.numFDefs;
numIDefs := ins^.numIDefs;
maxFDefs := ins^.maxFDefs;
maxIDefs := ins^.maxIDefs;
FDefs := ins^.FDefs;
IDefs := ins^.IDefs;
maxFunc := ins^.maxFunc;
maxIns := ins^.maxIns;
metrics := ins^.metrics;
codeRangeTable := ins^.codeRangeTable;
storeSize := ins^.storeSize;
storage := ins^.storage;
twilight := ins^.twilight;
Update_Max( stackSize,
sizeof(Long),
stack,
face^.maxProfile.maxStackElements+32 );
Update_Max( loadSize,
sizeof(TSubglyph_Record),
loadStack,
face^.maxComponents+1 );
Update_Max( glyphSize,
sizeof(Byte),
glyphIns,
face^.maxProfile.maxSizeOfInstructions );
Update_Points( face^.maxPoints+2, face^.maxContours, exec );
pts.n_points := 0;
pts.n_contours := 0;
instruction_trap := false;
GS := ins^.GS;
cvtSize := ins^.cvtSize;
cvt := ins^.cvt;
end;
end;
procedure Context_Save( exec : PExec_Context;
ins : PInstance );
begin
with ins^ do
begin
error := exec^.error;
numFDefs := exec^.numFDefs;
numIDefs := exec^.numIDefs;
maxFunc := exec^.maxFunc;
maxIns := exec^.maxIns;
codeRangeTable := exec^.codeRangeTable;
GS := exec^.GS;
end;
end;
function Instance_Destroy( instance : Pointer ) : TError;
var
ins : PInstance;
begin
Instance_Destroy := Success;
ins := PInstance(instance);
if ins = nil then
exit;
with ins^ do
begin
if debug then
begin
context := nil;
debug := false;
end;
Free( twilight.org );
Free( twilight.cur );
Free( twilight.flags );
twilight.n_points := 0;
Free( cvt );
cvtSize := 0;
Free( storage );
storeSize := 0;
Free( FDefs );
Free( IDefs );
numFDefs := 0;
numIDefs := 0;
maxFDefs := 0;
maxIDefs := 0;
owner := nil;
valid := false;
end;
end;
function Instance_Create( _ins : Pointer;
_face : Pointer ) : TError;
label
Fail_Memory;
var
l : Longint;
ins : PInstance;
face : PFace;
n_twilight : Int;
begin
Instance_Create := Failure;
if (_face = nil) then
Panic1('TTInst.Init_Instance : void argument' );
face := PFace(_face);
ins := PInstance(_ins);
ins^.owner := face;
with face^, ins^ do
begin
maxFDefs := maxProfile.maxFunctionDefs;
maxIDefs := maxProfile.maxInstructionDefs;
storeSize := maxProfile.maxStorage;
n_twilight := maxProfile.maxTwilightPoints;
if Alloc( FDefs, maxFDefs * sizeof(TDefRecord) ) or
Alloc( IDefs, maxIDefs * sizeof(TDefRecord) ) or
Alloc( storage, storeSize * sizeof(Long) ) or
Alloc( twilight.org, 2* n_twilight * sizeof(TT_F26Dot6) ) or
Alloc( twilight.cur, 2* n_twilight * sizeof(TT_F26Dot6) ) or
Alloc( twilight.flags, n_twilight )
then goto Fail_Memory;
twilight.n_points := n_twilight;
metrics.x_resolution := 96;
metrics.y_resolution := 96;
metrics.pointSize := 10;
metrics.x_scale2 := 1;
metrics.y_scale2 := 1;
metrics.scale2 := 1;
cvtSize := face^.cvtSize;
if Alloc( cvt, cvtSize * sizeof(Long) ) then
goto Fail_Memory;
end;
Instance_Create := Success;
exit;
Fail_Memory:
Instance_Destroy(ins);
error := TT_Err_Out_Of_Memory;
exit;
end;
function Instance_Init( ins : PInstance ) : TError;
var
exec : PExec_Context;
face : PFace;
label
Fin;
begin
Instance_Init := Failure;
face := ins^.owner;
if ins^.debug then
exec := ins^.context
else
exec := New_Context( ins );
if exec = nil then
begin
error := TT_Err_Could_Not_Find_Context;
exit;
end;
with ins^ do begin
GS := Default_GraphicsState;
numFDefs := 0;
numIDefs := 0;
maxFunc := -1;
maxIns := -1;
end;
Context_Load( exec, ins );
with exec^ do
begin
callTop := 0;
top := 0;
period := 64;
phase := 0;
threshold := 0;
with metrics do
begin
x_ppem := 10;
y_ppem := 10;
pointSize := 10;
x_scale1 := 0;
x_scale2 := 1;
y_scale1 := 0;
y_scale2 := 1;
scale1 := 0;
scale2 := 1;
ratio := 1 shl 16;
end;
instruction_trap := false;
cvtSize := ins^.cvtSize;
cvt := ins^.cvt;
F_dot_P := $10000;
end;
Set_CodeRange( exec,
TT_CodeRange_Font,
face^.fontProgram,
face^.fontPgmSize );
Clear_CodeRange( exec, TT_CodeRange_Cvt );
Clear_CodeRange( exec, TT_CodeRange_Glyph );
if face^.fontPgmSize > 0 then
begin
if Goto_CodeRange( exec, TT_CodeRange_Font, 0 ) then
goto Fin;
if Run_Ins( @exec^ ) then
begin
error := exec^.error;
goto Fin;
end;
end;
Instance_Init := Success;
Fin:
Context_Save( exec, ins );
if not ins^.debug then
Done_Context( exec );
ins^.valid := False;
end;
function Instance_Reset( ins : PInstance;
debug : boolean ) : TError;
var
exec : PExec_Context;
face : PFace;
i : Int;
label
Fin;
begin
Instance_Reset := Failure;
if ins^.valid then
begin
Instance_Reset := Success;
exit;
end;
face := ins^.owner;
with ins^.metrics do
begin
if x_ppem < 1 then x_ppem := 1;
if y_ppem < 1 then y_ppem := 1;
if x_ppem >= y_ppem then
begin
scale1 := x_scale1;
scale2 := x_scale2;
ppem := x_ppem;
x_ratio := 1 shl 16;
y_ratio := MulDiv_Round( y_ppem, $10000, x_ppem );
end
else
begin
scale1 := y_scale1;
scale2 := y_scale2;
ppem := y_ppem;
x_ratio := MulDiv_Round( x_ppem, $10000, y_ppem );
y_ratio := 1 shl 16
end;
end;
for i := 0 to ins^.cvtSize-1 do
ins^.cvt^[i] := MulDiv_Round( ins^.owner^.cvt^[i],
ins^.metrics.scale1,
ins^.metrics.scale2 );
ins^.GS := Default_GraphicsState;
if ins^.debug then
exec := ins^.context
else
exec := New_Context(ins);
if exec = nil then
begin
error := TT_Err_Could_Not_Find_Context;
exit;
end;
Context_Load( exec, ins );
Set_CodeRange( exec,
TT_CodeRange_CVT,
face^.cvtProgram,
face^.cvtPgmSize );
Clear_CodeRange( exec, TT_CodeRange_Glyph );
with exec^ do
begin
for i := 0 to storeSize-1 do
storage^[i] := 0;
instruction_trap := False;
top := 0;
callTop := 0;
for i := 0 to twilight.n_points-1 do
begin
twilight.org^[i].x := 0;
twilight.org^[i].y := 0;
twilight.cur^[i].x := 0;
twilight.cur^[i].y := 0;
end;
end;
if face^.cvtPgmSize > 0 then
if Goto_CodeRange( exec, TT_CodeRange_CVT, 0 ) or
( (not debug) and Run_Ins( @exec^ ) ) then
goto Fin;
ins^.GS := exec^.GS;
Instance_Reset := Success;
Fin:
Context_Save( exec, ins );
if not ins^.debug then
Done_Context(exec);
if error = 0 then
ins^.valid := True;
end;
function Face_Destroy( _face : Pointer ) : TError;
var
face : PFace;
n : Int;
begin
Face_Destroy := Success;
face := PFace(_face);
if face = nil then exit;
Cache_Destroy( face^.instances );
Cache_Destroy( face^.glyphs );
Free( face^.dirTables );
face^.numTables := 0;
Free( face^.glyphLocations );
face^.numLocations := 0;
for n := 0 to face^.numCMaps-1 do
CharMap_Free( face^.cMaps^[n] );
Free( face^.cMaps );
face^.numCMaps := 0;
Free( face^.cvt );
face^.cvtSize := 0;
Free( face^.horizontalHeader.short_metrics );
Free( face^.horizontalHeader.long_metrics );
if face^.verticalInfo then
begin
Free( face^.verticalHeader.short_metrics );
Free( face^.verticalHeader.long_metrics );
face^.verticalInfo := False;
end;
Free( face^.fontProgram );
Free( face^.cvtProgram );
face^.fontPgmSize := 0;
face^.cvtPgmSize := 0;
Free( face^.gasp.gaspRanges );
Free( face^.nameTable.names );
Free( face^.nameTable.storage );
face^.nameTable.numNameRecords := 0;
face^.nameTable.format := 0;
for n := 0 to face^.hdmx.num_records-1 do
Free( face^.hdmx.records^[n].widths );
Free( face^.hdmx.records );
face^.hdmx.num_records := 0;
TT_Close_Stream( face^.stream );
end;
function Face_Create( _face : Pointer;
_input : Pointer ) : TError;
var
input : PFont_Input;
face : PFace;
label
Fail;
begin
Face_Create := Failure;
face := PFace(_face);
input := PFont_Input(_input);
face^.stream := input^.stream;
if Cache_Create( objs_instance_class, face^.instances ) or
Cache_Create( objs_glyph_class, face^.glyphs ) then exit;
if Load_TrueType_Directory( face, input^.fontIndex ) then
exit;
if Load_TrueType_Header ( face ) or
Load_TrueType_MaxProfile ( face ) or
Load_TrueType_Locations ( face ) or
Load_TrueType_CMap ( face ) or
Load_TrueType_CVT ( face ) or
Load_TrueType_Metrics_Header ( face, false ) or
Load_TrueType_Programs ( face ) or
Load_TrueType_Gasp ( face ) or
Load_TrueType_Names ( face ) or
Load_TrueType_OS2 ( face ) or
Load_TrueType_Hdmx ( face ) or
Load_TrueType_Postscript ( face ) or
Load_TrueType_Metrics_Header ( face, true ) then
goto Fail;
Face_Create := Success;
exit;
Fail:
Face_Destroy( face );
end;
function Glyph_Destroy( _glyph : Pointer ) : TError;
var
glyph : PGlyph;
begin
Glyph_Destroy := Success;
glyph := PGlyph(_glyph);
if glyph = nil then
exit;
glyph^.outline.owner := true;
TT_Done_Outline( glyph^.outline );
end;
function Glyph_Create( _glyph : Pointer;
_face : Pointer ) : TError;
var
glyph : PGlyph;
begin
glyph := PGlyph(_glyph);
glyph^.face := PFace(_face);
error := TT_New_Outline( glyph^.face^.maxPoints+2,
glyph^.face^.maxContours,
glyph^.outline );
if error <> TT_Err_Ok then
Glyph_Create := Failure
else
Glyph_Create := Success;
end;
function Scale_X( var metrics : TIns_Metrics; x : TT_Pos ) : TT_Pos;
begin
Scale_X := MulDiv_Round( x, metrics.x_scale1, metrics.x_scale2 );
end;
function Scale_Y( var metrics : TIns_Metrics; y : TT_Pos ) : TT_Pos;
begin
Scale_Y := MulDiv_Round( y, metrics.y_scale1, metrics.y_scale2 );
end;
function TTObjs_Init : TError;
begin
TTObjs_Init := Failure;
Cache_Create( objs_face_class, face_cache );
Cache_Create( objs_exec_class, exec_cache );
TTObjs_Init := success;
end;
procedure TTObjs_Done;
begin
Cache_Destroy( face_cache );
Cache_Destroy( exec_cache );
end;
end.