1
0
Files
applications
bindings
components
Comba_Animation
aboutcomponent
acs
beepfp
callite
captcha
chelper
chemtext
cmdline
cmdlinecfg
colorpalette
cryptini
csvdocument
epiktimer
everettrandom
examplecomponent
exctrls
extrasyn
fpexif
fpsound
fpspreadsheet
fractions
freetypepascal
freetype.pas
lazfreetype.lpk
lazfreetype.pas
ttcache.pas
ttcalc.pas
ttcalc1.inc
ttcalc2.inc
ttcalc3.inc
ttcalc4.inc
ttcmap.pas
ttconfig.inc
ttdebug.pas
tterror.pas
ttfile.pas
ttgload.pas
ttinterp.pas
ttload.pas
ttmemory.pas
ttobjs.pas
ttraster.pas
tttables.pas
tttypes.pas
geckoport
gradcontrols
grid_semaphor
gridprinter
industrialstuff
iosdesigner
iphonelazext
jujiboutils
jvcllaz
kcontrols
lazautoupdate
lazbarcodes
lazmapviewer
lclextensions
longtimer
manualdock
mbColorLib
mplayer
multithreadprocs
nicechart
nicegrid
nicesidebar
nvidia-widgets
onguard
orpheus
playsoundpackage
poweredby
powerpdf
rgbgraphics
richmemo
richview
rtfview
rx
scrolltext
smnetgradient
spktoolbar
splashabout
svn
systools
tdi
thtmlport
tparadoxdataset
tvplanit
xdev_toolkit
zlibar
zmsql
examples
image_sources
lclbindings
wst
lazarus-ccr/components/freetypepascal/ttobjs.pas

1948 lines
61 KiB
ObjectPascal
Raw Normal View History

(*******************************************************************
*
* ttobjs.pas 2.0
*
* Objects definition unit.
*
* Copyright 1996, 1997 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
******************************************************************)
(* *)
(* The four important objects managed by the library are : *)
(* *)
(* Face : the object for a given typeface *)
(* Instance : the object for a face's given pointsize/transform *)
(* Context : the object for a given glyph loading/hinting execution *)
(* Glyph : the object for a given glyph ( outline and metrics ) *)
(* *)
(* A Face object is described by a TFace record, and its *)
(* associated sub-tables. It is created through a call to the *)
(* 'TT_Open_Face' API. *)
(* *)
(* An Instance object is described by a TInstance record, and *)
(* sub-tables. It is created for a given face through a call to the *)
(* 'TT_Open_Instance' API. Several instances can share the same face *)
(* *)
(* The pointsize and/or transform of a given instance object can be *)
(* changed on the fly through a call to the 'TT_Reset_Instance' API. *)
(* *)
(* A Glyph object is used to describe a glyph to the client application *)
(* It is made of a TGlyph_Record header, with several sub-tables used *)
(* to store, for example, point coordinates or outline info.. *)
(* It can hold metrics information and other attributes, as well as *)
(* the glyph's outline. A client application can request any kind of *)
(* info to the library on a given glyph through the 'TT_Get_Glyph' *)
(* call. *)
(* *)
(* *)
(* A Context is described by a TExec_Context record, and sub-tables *)
(* Execution contexts are created on demand during the following *)
(* operations : *)
(* *)
(* - creating a new instance ( to read and execute the font program ) *)
(* - setting/resetting the pointsize ( to execute the CVT program ) *)
(* - during glyph loading ( when hinting is on ) *)
(* *)
(* They are used to run TrueType instructions and load/store *)
(* glyph data that are not part of the Glyph object ( as they're of *)
(* no meaning to a client application ). *)
(* *)
(* The library keeps track of all objects related to a given face : *)
(* *)
(* A face's instances are kept in two linked lists : one is the 'active' *)
(* list, which tracks the face's current opened instances, while the *)
(* other is the 'idle' list used to collect/recycle instance objects *)
(* when they become unuseful after a 'TT_Close_Instance' call. *)
(* *)
(* In the same way, a face's execution contexts are kept in two *)
(* similar lists. Note that, as contexts are created on demand, *)
(* the active and idle contexts lists should always contain few *)
(* elements. *)
(* *)
(* Look also for the following files : *)
(* *)
(* Face manager : TTFace.pas *)
(* Instance manager : TTInst.pas *)
(* Context manager : TTExec.pas *)
(* Glyph manager : TTGlyph.pas *)
(* *)
unit TTObjs;
interface
{$mode Delphi}
{$I TTCONFIG.INC}
uses FreeType,
TTTypes,
TTError,
TTCache,
TTTables,
TTCMap;
type
(* Graphics State *)
(* *)
(* The Graphics State (GS) is managed by the *)
(* instruction field, but does not come from *)
(* the font file. Thus, we can use 'int's *)
(* where needed. *)
(* *)
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
);
(**********************************************************************)
(* *)
(* Execution Subtables : *)
(* *)
(**********************************************************************)
const
MaxCodeRanges = 3;
(* There can only be 3 active code ranges at once : *)
(* - the Font Program *)
(* - the CVT Program *)
(* - a glyph's instructions set *)
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;
(* defines a code range *)
(* *)
(* code ranges can be resident to a glyph ( i.e. the Font Program) *)
(* while some others are volatile ( Glyph instructions ) *)
(* tracking the state and presence of code ranges allows function *)
(* and instruction definitions within a code range to be forgotten *)
(* when the range is discarded *)
TCodeRangeTable = array[1..MaxCodeRanges] of TCodeRange;
(* defines a function/instruction definition record *)
PDefRecord = ^TDefRecord;
TDefRecord = record
Range : Int; (* in which code range is it located ? *)
Start : Int; (* where does it start ? *)
Opc : Byte; (* function #, or instruction code *)
Active : boolean; (* is the entry active ? *)
end;
PDefArray = ^TDefArray;
TDefArray = array[0..99] of TDefRecord;
(* defines a call record, used to manage function calls *)
TCallRecord = record
Caller_Range : Int;
Caller_IP : Int;
Cur_Count : Int;
Cur_Restart : Int;
end;
(* defines a simple call stack *)
TCallStack = array[0..99] of TCallRecord;
PCallStack = ^TCallStack;
PGlyph_Zone = ^TGlyph_Zone;
TGlyph_Zone = record
n_points : Int;
n_contours : Int;
org : TT_Points; (* original (scaled) coords *)
cur : TT_Points; (* current coordinates *)
flags : TT_PTouchTable;
conEnds : PUShort;
end;
TRound_Function = function( distance, compensation : TT_F26dot6 )
: TT_F26dot6;
(* Rounding function, as used by the interpreter *)
TMove_Function = procedure( zone : PGlyph_Zone;
point : Int;
distance : TT_F26dot6 );
(* Point displacement along the freedom vector routine, as *)
(* used by the interpreter *)
TProject_Function = function( var P1, P2 : TT_Vector ) : TT_F26dot6;
(* Distance projection along one of the proj. vectors, as used *)
(* by the interpreter *)
TFunc_Get_CVT = function ( index : Int ) : TT_F26Dot6;
(* Reading a cvt value. Take care of non-square pixels when *)
(* needed *)
TFunc_Set_CVT = procedure( index : Int; value : TT_F26Dot6 );
(* Setting or Moving a cvt value. Take care of non-square *)
(* pixels when needed *)
(********************************************************************)
(* *)
(* Glyph Sub-Tables *)
(* *)
(********************************************************************)
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;
(* A note regarding non-squared pixels : *)
(* *)
(* ( This text will probably go into some docs at some time, for *)
(* now, it is kept there to explain some definitions in the *)
(* TIns_Metrics record ). *)
(* *)
(* The CVT is a one-dimensional array containing values that *)
(* control certain important characteristics in a font, like *)
(* the height of all capitals, all lowercase letter, default *)
(* spacing or stem width/height. *)
(* *)
(* These values are found in FUnits in the font file, and must be *)
(* scaled to pixel coordinates before being used by the CVT and *)
(* glyph programs. Unfortunately, when using distinct x and y *)
(* resolutions ( or distinct x and y pointsizes ), there are two *)
(* possible scalings. *)
(* *)
(* A first try was to implement a 'lazy' scheme were all values *)
(* were scaled when first used. However, some values are always *)
(* used in the same direction, and some other are used in many *)
(* different circumstances and orientations. *)
(* *)
(* I have found a simpler way to do the same, and it even seems to *)
(* work in most of the cases : *)
(* *)
(* - all CVT values are scaled to the maximum ppem size *)
(* *)
(* - when performing a read or write in the CVT, a ratio factor *)
(* is used to perform adequate scaling. Example : *)
(* *)
(* x_ppem = 14 *)
(* y_ppem = 10 *)
(* *)
(* we chose ppem = x_ppem = 14 as the CVT scaling size. All cvt *)
(* entries are scaled to it. *)
(* *)
(* x_ratio = 1.0 *)
(* y_ratio = y_ppem/ppem ( < 1.0 ) *)
(* *)
(* we compute the current ratio like : *)
(* *)
(* - if projVector is horizontal, ratio = x_ratio = 1.0 *)
(* - if projVector is vertical, ratop = y_ratio *)
(* - else, ratio = sqrt( (proj.x*x_ratio)�+(proj.y*y_ratio)� ) *)
(* *)
(* reading a cvt value returns ratio*cvt[index] *)
(* writing a cvt value in pixels cvt[index]/ratio *)
(* *)
(* the current ppem is simple ratio*ppem *)
(* *)
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;
(* for non-square pixels *)
x_ratio : Long;
y_ratio : Long;
scale1 : Long;
scale2 : Long;
ppem : Int;
ratio : Long;
(* compensations *)
compensations : array[0..3] of TT_F26Dot6;
(* flags *)
rotated : Boolean;
stretched : Boolean;
end;
(********************************************************************)
(* *)
(* FreeType Face Object *)
(* *)
(********************************************************************)
PFace = ^TFace;
PInstance = ^TInstance;
PExec_Context = ^TExec_Context;
TFace = record
stream : TT_Stream;
(* i/o stream *)
ttcHeader : TTTCHeader;
(* TrueType collection header, if any was found *)
maxProfile : TMaxProfile;
(* maximum profile table, as defined by the TT Spec *)
(* Note : *)
(* it seems that some maximum values cannot be *)
(* taken directly from this table, but rather by *)
(* combining some of its fields ( e.g. the max. *)
(* number of points seems to be given by *)
(* MAX( maxPoints, maxCompositePoints ) *)
(* *)
(* For this reason, we define later our own *)
(* max values that are used to load and allocate *)
(* further tables.. *)
fontHeader : TT_Header;
(* the font header as defined by the TT Spec *)
horizontalHeader : TT_Horizontal_Header;
(* the horizontal header, as defined in the spec *)
verticalInfo : Boolean;
(* set to true when vertical data is in the font *)
verticalHeader : TT_Vertical_Header;
(* vertical header table *)
os2 : TT_OS2;
(* 'OS/2' table *)
postscript : TT_Postscript;
(* 'Post' table *)
hdmx : THdmx;
(* 'hdmx' = horizontal device metrics table *)
nameTable : TName_Table;
(* 'name' = name table *)
numTables : Int;
dirTables : PTableDirEntries;
(* The directory of the TrueType tables found in *)
(* this face's stream *)
numCMaps : Int;
cMaps : PCMapTables;
(* the directory of character mappings tables found *)
(* for this face.. *)
numLocations : Int;
glyphLocations : PStorage;
(* the glyph locations table *)
(* the hmtx table is now within the horizontal header *)
fontPgmSize : Int;
fontProgram : PByte;
(* the font program, if any.. *)
cvtPgmSize : Int;
cvtProgram : PByte;
(* the cvt (or 'prep') program, if any.. *)
cvtSize : Int;
cvt : PShort;
(* the original, unscaled, control value table *)
gasp : TGasp;
(* the following values must be set by the *)
(* maximum profile loader.. *)
numGlyphs : Int;
(* the face's total number of glyphs *)
maxPoints : Int;
(* max glyph points number, simple and composite *)
maxContours : Int;
(* max glyph contours number, simple and composite *)
maxComponents : Int;
(* max components in a composite glyph *)
(* the following lists are used to track active *)
(* instance and context objects, as well as *)
(* to recycle them.. *)
(* see 'TTLists'.. *)
instances : TCache;
glyphs : TCache;
(* various caches for this face's child objects *)
extension : Pointer;
(* a typeless pointer to the face object's extensions *)
generic : Pointer;
(* generic pointer - see TT_Set/Get_Face_Pointer *)
end;
(********************************************************************)
(* *)
(* FreeType Instance Object *)
(* *)
(********************************************************************)
TInstance = record
owner : PFace;
valid : Boolean;
metrics : TIns_Metrics;
numFDefs : Int; (* number of function defs *)
maxFDefs : Int;
FDefs : PDefArray; (* table of FDefs entries *)
numIDefs : Int; (* number of instruction defs *)
maxIDefs : Int;
IDefs : PDefArray; (* table of IDefs entries *)
maxFunc : Int; (* maximum function number *)
maxIns : Int; (* maximum instruction number *)
codeRangeTable : TCodeRangeTable;
GS : TGraphicsState;
storeSize : Int;
storage : PStorage;
(* the storage area *)
cvtSize : Int;
cvt : PLong;
(* the scaled control value table *)
twilight : TGlyph_Zone;
(* the instance's twilight zone *)
(* debugging variables *)
debug : Boolean;
context : PExec_Context;
(* when using the debugger, we must keep the *)
(* execution context with the instance object *)
(* rather than asking it on demand *)
generic : Pointer;
(* generic pointer - see TT_Set/Get_Instance_Pointer *)
end;
(********************************************************************)
(* *)
(* FreeType Execution Context Object *)
(* *)
(********************************************************************)
TExec_Context = record
face : PFace;
instance : PInstance;
error : Int;
stackSize : Int; (* size of instance stack *)
top : Int; (* top of instance stack *)
stack : PStorage; (* current instance stack *)
args : Int; (* number of arguments in opcode *)
new_top : Int; (* new stack top after opc. exec *)
zp0,
zp1,
zp2,
twilight,
pts : TGlyph_Zone;
GS : TGraphicsState;
curRange : Int; (* current code range number *)
code : PByte; (* current code range *)
IP : Int; (* current instruction pointer *)
codeSize : Int; (* size of current range *)
opcode : Byte; (* current opcode *)
length : Int; (* length of current opcode *)
step_ins : boolean; (* used by the interpreter *)
(* if true, go to the next *)
(* instruction.. *)
loadSize : Int;
loadStack : PSubglyph_Stack;
(* the load stack used to load composite glyphs *)
glyphIns : PByte; (* glyph instructions *)
glyphSize : Int; (* glyph ins. size *)
callTop : Int;
callSize : Int;
callStack : PCallStack; (* interpreter call stack *)
period, (* values used for the *)
phase, (* 'SuperRounding' *)
threshold : TT_F26dot6;
maxPoints : Int;
maxContours : Int;
(* the following are copies of the variables found *)
(* in an instance object *)
numFDefs : Int; (* number of function defs *)
maxFDefs : Int;
FDefs : PDefArray; (* table of FDefs entries *)
numIDefs : Int; (* number of instruction defs *)
maxIDefs : Int;
IDefs : PDefArray; (* table of IDefs entries *)
maxFunc : Int; (* maximum function number *)
maxIns : Int; (* maximum instruction number *)
codeRangeTable : TCodeRangeTable;
storeSize : Int; (* size of current storage *)
storage : PStorage; (* storage area *)
metrics : TIns_Metrics;
cur_ppem : Int;
scale1 : Long;
scale2 : Long;
cached_metrics : Boolean;
(*
numContours : Int;
endContours : PUShort;
*)
Instruction_Trap : Boolean;
(* used by the full-screen debugger. If set, the *)
(* interpreter will exit after executing one *)
(* opcode. Used to perform single-stepping.. *)
is_composite : Boolean;
(* this flag is true when the glyph is a composite *)
(* one. In this case, we measure original distances *)
(* in the loaded coordinates (font units), then *)
(* scale them appropriately. This get rids of *)
(* transformation artifacts (like symetries..) *)
cvtSize : Int;
cvt : PLong;
(* these variables are proper to the context *)
F_dot_P : Long;
(* the dot product of the free and projection *)
(* vector is used in frequent operations.. *)
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;
(* single width ? *)
end;
(********************************************************************)
(* *)
(* FreeType Glyph Object *)
(* *)
(********************************************************************)
PGlyph = ^TGlyph;
TGlyph = record
face : PFace;
metrics : TT_Big_Glyph_Metrics;
outline : TT_Outline;
(* temporary - debugging purposes *)
computed_width : Int;
precalc_width : Int;
is_composite : Boolean;
end;
PFont_Input = ^TFont_Input;
TFont_Input = record
stream : TT_Stream; (* inpute stream *)
fontIndex : Int; (* index of font in collection *)
end;
(****************************************************************)
(* *)
(* Code Range Functions *)
(* *)
(****************************************************************)
function Goto_CodeRange( exec : PExec_Context;
range : Int;
IP : Int ) : TError;
(* Go to a specified coderange *)
function Get_CodeRange( exec : PExec_Context;
range : Int ) : PCodeRange;
(* return a pointer to a given coderange record *)
(* used only by the debugger *)
function Set_CodeRange( exec : PExec_Context;
range : Int;
base : Pointer;
length : Int ) : TError;
(* Set a given code range properties *)
function Clear_CodeRange( exec : PExec_Context;
range : Int ) : TError;
(* Clear a given code range *)
(****************************************************************)
(* *)
(* Management Functions *)
(* *)
(****************************************************************)
function New_Context( instance : PInstance ) : PExec_Context;
(* Get a new execution context, either fresh or recycled, for *)
(* an instance of the face 'res' *)
(* *)
(* Notes : - called by 'New_Face_Context' *)
(* - assumes that the face mutex is acquired *)
procedure Done_Context( exec : PExec_Context );
(* Releases an execution context. The context can be destroyed *)
(* or recycled, depending on implementation *)
(* *)
(* Notes : - called by 'Done_Face_Context' *)
(* - assumes that the face mutex is acquired *)
(****************************************************************)
(* *)
(* Instance Update Functions *)
(* *)
(****************************************************************)
procedure Context_Load( exec : PExec_Context;
ins : PInstance );
(* update exec's data with the one found in 'ins' *)
(* typically before an execution *)
procedure Context_Save( exec : PExec_Context;
ins : PInstance );
(* update ins's data with the one found in 'exec' *)
(* typically after an execution *)
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;
(* Initialize object manager *)
procedure TTObjs_Done;
(* Finalize object manager *)
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
*
* Description : gets a new active execution context for a given
* resident/face object.
*
* Input : aResident
*
* Output : Returns new exec. context. Nil in case of failure
*
* Notes : Don't forget to modify 'Free_Context' if you change
* the fields of a TExec_Context
*
******************************************************************)
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;
(*******************************************************************
*
* Function : Done_Context
*
* Description :
*
* Input : aResident
*
* Output : Discards an active execution context when it
* becomes unuseful. It is putin its face's recycle
* list
*
******************************************************************)
procedure Done_Context( exec : PExec_Context );
begin
if exec <> nil then
Cache_Done( exec_cache, Pointer(exec) );
end;
(*******************************************************************
*
* Function : New_Instance
*
* Description : gets a new active instance for a given
* face object.
*
* Input : face
*
* Output : Returns new instance. Nil in case of failure
*
******************************************************************)
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;
(*******************************************************************
*
* Function : Done_Instance
*
* Description :
*
* Input : instance
*
* Output : Discards an active instance when it
* becomes unuseful. It is put in its face's recycle
* list
*
******************************************************************)
procedure Done_Instance( instance : PInstance );
begin
if instance <> nil then
Cache_Done( instance^.owner^.instances, Pointer(instance) );
end;
(****************************************************************)
(* *)
(* Code Range Functions *)
(* *)
(****************************************************************)
(*******************************************************************
*
* Function : Goto_CodeRange
*
* Description : Switch to a new code range (updates Code and IP).
*
* Input : exec target execution context
* range new execution code range
* IP new IP in new code range
*
* Output : SUCCESS on success. FAILURE on error (no code range).
*
*****************************************************************)
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;
(* NOTE : Because the last instruction of a program may be a CALL *)
(* which will return to the first byte *after* the code *)
(* range, we test for IP <= Size, instead of IP < Size. *)
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
*
* Description : Returns a pointer to a given code range. Should
* be used only by the debugger. Returns NULL if
* 'range' is out of current bounds.
*
* Input : exec target execution context
* range new execution code range
*
* Output : Pointer to the code range record. NULL on failure.
*
*****************************************************************)
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
*
* Description : Sets a code range.
*
* Input : exec target execution context
* range code range index
* base new code base
* length sange size in bytes
*
* Output : SUCCESS on success. FAILURE on error.
*
*****************************************************************)
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
*
* Description : clears a code range.
*
* Input : exec target execution context
* range code range index
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes : Does not set the Error variable.
*
*****************************************************************)
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;
(****************************************************************)
(* *)
(* Management Functions *)
(* *)
(****************************************************************)
(*******************************************************************
*
* Function : Context_Destroy
*
* Description : Frees an execution context
*
* Input : context : execution context
*
* Notes : Allocation is found in the 'New_Context' function
*
******************************************************************)
function Context_Destroy( exec : Pointer ) : TError;
begin
Context_Destroy := Success;
if exec = nil then exit;
with PExec_Context(exec)^ do
begin
(* Free contours array *)
Free( pts.conEnds );
pts.n_contours := 0;
Free( pts.cur );
Free( pts.org );
Free( pts.flags );
pts.n_points := 0;
(* Free stack *)
Free( stack );
stackSize := 0;
(* Free call stack *)
Free( callStack );
callSize := 0;
callTop := 0;
(* Free composite load stack *)
Free( loadStack );
(* free glyph code range *)
Free( glyphIns );
glyphSize := 0;
instance := nil;
face := nil;
end;
end;
(*******************************************************************
*
* Function : Context_Create
*
* Description : Creates a new execution context
*
* Input : _context context record
* _face face record
*
******************************************************************)
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;
(* Allocate a little extra for broken fonts like Courbs.ttf *)
(* and Timesbs.ttf *)
n_points := face^.maxPoints + 2;
(* Reserve glyph code range *)
if Alloc( glyphIns, face^.MaxProfile.maxSizeOfInstructions ) or
(* Reserve call stack *)
Alloc( callStack, callSize*sizeof(TCallRecord) ) or
(* Reserve stack *)
Alloc( stack, stackSize*sizeof(Long) ) then
(* we don't reserve the points and contours arrays anymore *)
(* as this will be performed automatically by a Context_Load *)
(* the same is true for the load stack *)
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
*
* Description : Run a glyph's bytecode stream
*
* Input : exec context record
*
******************************************************************)
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;
(****************************************************************)
(* *)
(* Instance Update Functions *)
(* *)
(****************************************************************)
(*******************************************************************
*
* Function : Context_Load
*
* Description : loads instance data into a new execution context
*
*******************************************************************)
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;
(* We reserve some extra space to deal with broken fonts *)
(* like Arial BS, Courier BS, etc.. *)
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 );
(* XXXX : Don't forget the phantom points !! *)
Update_Points( face^.maxPoints+2, face^.maxContours, exec );
pts.n_points := 0;
pts.n_contours := 0;
instruction_trap := false;
(* Set default graphics state *)
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;
(* Set default graphics state *)
GS := exec^.GS;
end;
end;
(*******************************************************************
*
* Function : Instance_Destroy
*
* Description : The Instance Record destructor.
*
*****************************************************************)
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 zone *)
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
*
* Description : The Instance constructor.
*
* This functions creates a new instance object for a given face
*
*****************************************************************)
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;
{$IFDEF ASSERT}
if (_face = nil) then
Panic1('TTInst.Init_Instance : void argument' );
{$ENDIF}
face := PFace(_face);
ins := PInstance(_ins);
ins^.owner := face;
with face^, ins^ do
begin
(* Reserve function and instruction defs arrays *)
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;
{ Reserve Control Value Table }
cvtSize := face^.cvtSize;
if Alloc( cvt, cvtSize * sizeof(Long) ) then
goto Fail_Memory;
end;
Instance_Create := Success;
exit;
Fail_Memory:
Instance_Destroy(ins);
(* free all partially allocated tables, including the instance record *)
error := TT_Err_Out_Of_Memory;
exit;
end;
(*******************************************************************
*
* Function : Instance_Init
*
* Description : Initializes a fresh new instance
* Executes the font program if any is found
*
* Input : ins the instance object to initialise
*
*****************************************************************)
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 );
(* debugging instances have their own context *)
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 );
(* Allow font program execution *)
Clear_CodeRange( exec, TT_CodeRange_Cvt );
Clear_CodeRange( exec, TT_CodeRange_Glyph );
(* disable CVT and glyph programs coderanges *)
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
*
* Description : Reset an instance to a new pointsize
* Executes the prep/cvt program if any is found
*
* Input : ins the instance object to initialise
*
*****************************************************************)
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;
(* compute new transform *)
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;
(* scale the cvt values to the new ppem *)
for i := 0 to ins^.cvtSize-1 do
ins^.cvt^[i] := MulDiv_Round( ins^.owner^.cvt^[i],
ins^.metrics.scale1,
ins^.metrics.scale2 );
(* Note that we use the y resolution by default to scale the cvt *)
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;
(* all twilight points are originally zero *)
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
*
* Description : The face object destructor
*
*****************************************************************)
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 );
(* freeing the tables directory *)
Free( face^.dirTables );
face^.numTables := 0;
(* freeing the locations table *)
Free( face^.glyphLocations );
face^.numLocations := 0;
(* freeing the character mapping tables *)
for n := 0 to face^.numCMaps-1 do
CharMap_Free( face^.cMaps^[n] );
Free( face^.cMaps );
face^.numCMaps := 0;
(* freeing the CVT *)
Free( face^.cvt );
face^.cvtSize := 0;
(* freeing the horizontal header *)
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;
(* freeing the programs *)
Free( face^.fontProgram );
Free( face^.cvtProgram );
face^.fontPgmSize := 0;
face^.cvtPgmSize := 0;
(* freeing the gasp table - none yet *)
Free( face^.gasp.gaspRanges );
(* freeing the names table *)
Free( face^.nameTable.names );
Free( face^.nameTable.storage );
face^.nameTable.numNameRecords := 0;
face^.nameTable.format := 0;
(* freeing the hdmx table *)
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
*
* Description : The face object constructor
*
*****************************************************************)
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;
(* Load collection directory if present *)
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.