lazarus/components/lazutils/lazfreetypefontcollection.pas
sekelsenmat 85011c746f Patch with font collection support from Circular
git-svn-id: trunk@36741 -
2012-04-13 07:01:31 +00:00

817 lines
22 KiB
ObjectPascal

unit LazFreeTypeFontCollection;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, EasyLazFreeType, AvgLvlTree, LazFreeType, TTTypes;
type
{ TFontCollectionItem }
TFontCollectionItem = class(TCustomFontCollectionItem)
private
FFilename: string;
FInformation: array[TFreeTypeInformation] of string;
FVersionNumber: string;
FStyleList: array of string;
FFace: TT_Face;
FFaceUsage: integer;
FUsePostscriptStyle: boolean;
procedure UpdateStyles;
procedure SetInformation(AIndex: TFreeTypeInformation; AValue: string);
procedure SetUsePostscriptStyle(AValue: boolean);
protected
function GetFilename: string; override;
function GetBold: boolean; override;
function GetInformation(AIndex: TFreeTypeInformation): string; override;
function GetItalic: boolean; override;
function GetStyleCount: integer; override;
function GetStyles: string; override;
function GetStyle(AIndex: integer): string; override;
function GetVersionNumber: string; override;
public
constructor Create(AFilename: string);
destructor Destroy; override;
function HasStyle(AStyle: string): boolean; override;
property Information[AIndex: TFreeTypeInformation]: string read GetInformation write SetInformation;
property VersionNumber: string read GetVersionNumber write FVersionNumber;
function CreateFont: TFreeTypeFont; override;
function QueryFace: TT_Face; override;
procedure ReleaseFace; override;
property UsePostscriptStyle: boolean read FUsePostscriptStyle write SetUsePostscriptStyle;
end;
{ TFamilyCollectionItem }
TFamilyCollectionItem = class(TCustomFamilyCollectionItem)
private
FFamilyName: string;
FFonts: array of TFontCollectionItem;
FFontCount: integer;
FStyles: array of string;
FStyleCount: integer;
FUsePostscriptStyle: boolean;
protected
function GetFontByIndex(AIndex: integer): TCustomFontCollectionItem; override;
function GetFontByStyles(AStyles: string): TCustomFontCollectionItem;
function GetFontIndexByStyles(AStyles: string): integer;
function GetStyle(AIndex: integer): string; override;
procedure AddStyle(AName: string);
function GetStyles: string; override;
function GetFamilyName: string; override;
function GetFontCount: integer; override;
function GetStyleCount: integer; override;
public
constructor Create(AName: string);
procedure AddFont(AFontItem: TFontCollectionItem);
function GetFont(const AStyles: array of string; NeedAllStyles: boolean = false; NoMoreStyle: boolean = false): TCustomFontCollectionItem; override;
function GetFont(AStyle: string; NeedAllStyles: boolean = false; NoMoreStyle: boolean = false): TCustomFontCollectionItem; override;
function GetFontIndex(const AStyles: array of string; NeedAllStyles: boolean = false; NoMoreStyle: boolean = false): integer; override;
function GetFontIndex(AStyle: string; NeedAllStyles: boolean = false; NoMoreStyle: boolean = false): integer; override;
function HasStyle(AName: string): boolean; override;
end;
{ TFreeTypeFontCollection }
TFreeTypeFontCollection = class(TCustomFreeTypeFontCollection)
private
FFontList: TAvgLvlTree;
FTempFont: TFreeTypeFont;
FUpdateCount: integer;
FFamilyList: TAvgLvlTree;
function AddFamily(AName: string): TFamilyCollectionItem;
function FindFamily(AName: string): TFamilyCollectionItem;
function FindFont(AFileName: string): TFontCollectionItem;
function CompareFontFileName({%H-} Tree: TAvgLvlTree; Data1, Data2: Pointer): integer;
function CompareFamilyName({%H-} Tree: TAvgLvlTree; Data1, Data2: Pointer): integer;
protected
function GetFont(AFileName: string): TCustomFontCollectionItem; override;
function GetFamily(AName: string): TCustomFamilyCollectionItem; override;
function GetFamilyCount: integer; override;
function GetFontCount: integer; override;
public
constructor Create; override;
procedure Clear; override;
procedure BeginUpdate; override;
procedure AddFolder(AFolder: string); override;
function AddFile(AFilename: string): boolean; override;
procedure EndUpdate; override;
destructor Destroy; override;
function FontFileEnumerator: IFreeTypeFontEnumerator; override;
function FamilyEnumerator: IFreeTypeFamilyEnumerator; override;
end;
implementation
type
{ TFamilyEnumerator }
TFamilyEnumerator = class(TInterfacedObject,IFreeTypeFamilyEnumerator)
private
FNodeEnumerator: TAvgLvlTreeNodeEnumerator;
public
constructor Create(ANodeEnumerator: TAvgLvlTreeNodeEnumerator);
destructor Destroy; override;
function MoveNext: boolean;
function GetCurrent: TCustomFamilyCollectionItem;
end;
{ TFontEnumerator }
TFontEnumerator = class(TInterfacedObject,IFreeTypeFontEnumerator)
private
FNodeEnumerator: TAvgLvlTreeNodeEnumerator;
public
constructor Create(ANodeEnumerator: TAvgLvlTreeNodeEnumerator);
destructor Destroy; override;
function MoveNext: boolean;
function GetCurrent: TCustomFontCollectionItem;
end;
{ TFontCollectionItem }
function TFontCollectionItem.GetStyles: string;
var i: integer;
begin
if StyleCount = 0 then
result := 'Regular'
else
begin
result := '';
for i := 0 to StyleCount-1 do
begin
if i > 0 then result += ' ';
result += Style[i];
end;
end;
end;
function TFontCollectionItem.GetInformation(AIndex: TFreeTypeInformation): string;
begin
if (AIndex < low(TFreeTypeInformation)) or (AIndex > high(TFreeTypeInformation)) then
result := ''
else
result := FInformation[AIndex];
end;
function TFontCollectionItem.GetBold: boolean;
begin
result := HasStyle('Bold');
end;
function TFontCollectionItem.GetItalic: boolean;
begin
result := HasStyle('Italic') or HasStyle('Oblique');
end;
function TFontCollectionItem.GetStyleCount: integer;
begin
result := length(FStyleList);
end;
procedure TFontCollectionItem.SetInformation(AIndex: TFreeTypeInformation;
AValue: string);
begin
if (AIndex >= low(TFreeTypeInformation)) and (AIndex <= high(TFreeTypeInformation)) then
begin
FInformation[AIndex] := AValue;
if ((AIndex = ftiStyle) and not FUsePostscriptStyle) or
((AIndex = ftiPostscriptName) and FUsePostscriptStyle) then UpdateStyles;
end;
end;
procedure TFontCollectionItem.SetUsePostscriptStyle(AValue: boolean);
begin
if AValue <> FUsePostscriptStyle then
begin
FUsePostscriptStyle:= AValue;
UpdateStyles;
end;
end;
function TFontCollectionItem.GetFilename: string;
begin
result := FFilename;
end;
function TFontCollectionItem.GetStyle(AIndex: integer): string;
begin
if (AIndex < 0) or (AIndex > high(FStyleList)) then
result := ''
else
result := FStyleList[AIndex];
end;
function TFontCollectionItem.GetVersionNumber: string;
begin
result := FVersionNumber;
end;
procedure TFontCollectionItem.UpdateStyles;
var
StyleStr: string;
idx,i: integer;
begin
if not FUsePostscriptStyle then
StyleStr := Information[ftiStyle]
else
begin
StyleStr := Information[ftiPostscriptName];
idx := pos('-',StyleStr);
if idx = 0 then StyleStr := 'Regular' else
begin
StyleStr := copy(StyleStr,idx+1,length(StyleStr)-idx);
for i := length(StyleStr) downto 2 do
if (StyleStr[i] = UpCase(StyleStr[i])) and
(StyleStr[i-1] <> UpCase(StyleStr[i-1])) then
Insert(' ',StyleStr,i);
if (length(StyleStr) > 2) and (copy(StyleStr, length(StyleStr)-2,3)=' MT') then
delete(StyleStr, length(StyleStr)-2,3);
end;
end;
FStyleList := StylesToArray(StyleStr);
end;
constructor TFontCollectionItem.Create(AFilename: string);
begin
FFilename:= AFilename;
FStyleList := nil;
FFaceUsage := 0;
FUsePostscriptStyle:= false;
end;
destructor TFontCollectionItem.Destroy;
begin
if FFaceUsage <> 0 then
begin
TT_Close_Face(FFace);
FFaceUsage := 0;
end;
inherited Destroy;
end;
function TFontCollectionItem.HasStyle(AStyle: string): boolean;
var i: integer;
begin
if CompareText(AStyle,'Regular')=0 then
begin
result := length(FStyleList)=0;
exit;
end;
for i := 0 to high(FStyleList) do
if CompareText(FStyleList[i],AStyle)=0 then
begin
result := true;
exit;
end;
result := false;
end;
function TFontCollectionItem.CreateFont: TFreeTypeFont;
begin
result := TFreeTypeFont.Create;
result.Name := Filename;
end;
function TFontCollectionItem.QueryFace: TT_Face;
var errorNum: TT_Error;
begin
if FFaceUsage = 0 then
begin
errorNum := TT_Open_Face(Filename,FFace);
if errorNum <> TT_Err_Ok then
raise exception.Create('Cannot open font (TT_Error ' + intToStr(errorNum)+')');
end;
result := FFace;
inc(FFaceUsage);
end;
procedure TFontCollectionItem.ReleaseFace;
begin
if FFaceUsage > 0 then
begin
dec(FFaceUsage);
if FFaceUsage = 0 then TT_Close_Face(FFace);
end;
end;
constructor TFontEnumerator.Create(ANodeEnumerator: TAvgLvlTreeNodeEnumerator);
begin
FNodeEnumerator := ANodeEnumerator;
end;
destructor TFontEnumerator.Destroy;
begin
FNodeEnumerator.Free;
end;
function TFontEnumerator.MoveNext: boolean;
begin
result := FNodeEnumerator.MoveNext;
end;
function TFontEnumerator.GetCurrent: TCustomFontCollectionItem;
begin
result := TCustomFontCollectionItem(FNodeEnumerator.Current.Data);
end;
{ TFamilyEnumerator }
function TFamilyEnumerator.GetCurrent: TCustomFamilyCollectionItem;
begin
result := TCustomFamilyCollectionItem(FNodeEnumerator.Current.Data);
end;
constructor TFamilyEnumerator.Create(ANodeEnumerator: TAvgLvlTreeNodeEnumerator );
begin
FNodeEnumerator := ANodeEnumerator;
end;
destructor TFamilyEnumerator.Destroy;
begin
FNodeEnumerator.Free;
end;
function TFamilyEnumerator.MoveNext: boolean;
begin
result := FNodeEnumerator.MoveNext;
end;
{ TFamilyCollectionItem }
function TFamilyCollectionItem.GetFontByIndex(AIndex: integer): TCustomFontCollectionItem;
begin
if AIndex = -1 then
result := GetFont('Regular')
else
if (AIndex < 0) or (AIndex >= FFontCount) then
result := nil
else
result := FFonts[AIndex];
end;
function TFamilyCollectionItem.GetFontByStyles(AStyles: string): TCustomFontCollectionItem;
var i: integer;
begin
for i := 0 to FFontCount-1 do
if CompareText(FFonts[i].Styles,AStyles)= 0 then
begin
result := FFonts[i];
exit;
end;
result := nil;
end;
function TFamilyCollectionItem.GetFontIndexByStyles(AStyles: string): integer;
var i: integer;
begin
for i := 0 to FFontCount-1 do
if CompareText(FFonts[i].Styles,AStyles)= 0 then
begin
result := i;
exit;
end;
result := -1;
end;
function TFamilyCollectionItem.GetStyle(AIndex: integer): string;
begin
if (AIndex < 0) or (AIndex >= FStyleCount) then
result := ''
else
result := FStyles[AIndex];
end;
procedure TFamilyCollectionItem.AddStyle(AName: string);
begin
if HasStyle(AName) then exit;
if FStyleCount = length(FStyles) then
setlength(FStyles, length(FStyles)+4);
FStyles[FStyleCount] := AName;
inc(FStyleCount);
end;
function TFamilyCollectionItem.GetStyles: string;
var i: integer;
begin
result := '';
for i := 0 to StyleCount-1 do
begin
if i <> 0 then result += ' ';
result += Style[i];
end;
end;
function TFamilyCollectionItem.GetFamilyName: string;
begin
result := FFamilyName;
end;
function TFamilyCollectionItem.GetFontCount: integer;
begin
result := FFontCount;
end;
function TFamilyCollectionItem.GetStyleCount: integer;
begin
result := FStyleCount;
end;
constructor TFamilyCollectionItem.Create(AName: string);
begin
FFamilyName:= AName;
FFontCount := 0;
FFonts := nil;
FStyleCount := 0;
FStyles := nil;
FUsePostscriptStyle:= false;
end;
procedure TFamilyCollectionItem.AddFont(AFontItem: TFontCollectionItem);
var i,j: integer;
DuplicateStyle: boolean;
StyleNumber: integer;
TempStyles,BaseStyle: string;
begin
if FFontCount = length(FFonts) then
setlength(FFonts, length(FFonts)+4);
FFonts[FFontCount] := AFontItem;
inc(FFontCount);
if FUsePostscriptStyle then AFontItem.UsePostscriptStyle := true;
for i := 0 to AFontItem.StyleCount -1 do
AddStyle(AFontItem.Style[i]);
DuplicateStyle := false;
for i := 0 to FFontCount-2 do
if FFonts[i].Styles = AFontItem.Styles then
begin
DuplicateStyle:= true;
break;
end;
if DuplicateStyle and not FUsePostscriptStyle then
begin //try with postscript styles instead
FUsePostscriptStyle:= true;
FStyleCount := 0;
DuplicateStyle := false;
for i := 0 to FFontCount-1 do
begin
FFonts[i].UsePostscriptStyle := true;
for j := 0 to FFonts[i].StyleCount -1 do
AddStyle(FFonts[i].Style[j]);
for j := 0 to i-1 do
if FFonts[j].Styles = FFonts[i].Styles then
begin
DuplicateStyle:= true;
break;
end;
end;
end;
if DuplicateStyle then
begin
StyleNumber := 1;
BaseStyle := AFontItem.Styles;
if BaseStyle = 'Regular' then BaseStyle := 'Unknown';
repeat
if StyleNumber = 1 then
TempStyles := BaseStyle
else
TempStyles := BaseStyle+' '+IntToStr(StyleNumber);
DuplicateStyle := false;
for i := 0 to FFontCount-2 do
if FFonts[i].Styles = TempStyles then
begin
DuplicateStyle:= true;
break;
end;
until not DuplicateStyle;
AFontItem.Information[ftiStyle] := TempStyles;
end;
if AFontItem.StyleCount = 0 then AddStyle('Regular');
end;
function TFamilyCollectionItem.GetFont(const AStyles: array of string;
NeedAllStyles: boolean; NoMoreStyle: boolean): TCustomFontCollectionItem;
var idx: integer;
begin
idx := GetFontIndex(AStyles,NeedAllStyles,NoMoreStyle);
if idx = -1 then result := nil
else result := Font[idx];
end;
function TFamilyCollectionItem.GetFontIndex(const AStyles: array of string; NeedAllStyles: boolean; NoMoreStyle: boolean): integer;
var curCount,curMissing,maxStyleCount,minMissingCount: integer;
bestMatch: integer;
i,j: integer;
begin
maxStyleCount := -1;
minMissingCount := 0;
bestMatch := -1;
for i := 0 to FontCount-1 do
begin
curCount := 0;
curMissing := 0;
for j := 0 to high(AStyles) do
if Font[i].HasStyle(AStyles[j]) then
inc(curCount);
curMissing := Font[i].StyleCount-curCount;
if NeedAllStyles and (curCount <> length(AStyles)) then continue;
if NoMoreStyle and (curMissing > 0) then continue;
if (curCount > maxStyleCount) or ((curCount = maxStyleCount) and (curMissing < minMissingCount)) then
begin
maxStyleCount := curCount;
minMissingCount:= curMissing;
bestMatch := i;
end;
end;
for i := 0 to FontCount-1 do
begin
curCount := 0;
curMissing := 0;
for j := 0 to high(AStyles) do
if Font[i].HasStyle(AStyles[j]) or
((CompareText(AStyles[j],'Italic')=0) and Font[i].HasStyle('Oblique')) or
((CompareText(AStyles[j],'Oblique')=0) and Font[i].HasStyle('Italic')) then
inc(curCount);
curMissing := Font[i].StyleCount-curCount;
if NeedAllStyles and (curCount <> length(AStyles)) then continue;
if NoMoreStyle and (curMissing > 0) then continue;
if (curCount > maxStyleCount) or ((curCount = maxStyleCount) and (curMissing < minMissingCount)) then
begin
maxStyleCount := curCount;
minMissingCount:= curMissing;
bestMatch := i;
end;
end;
result := bestMatch;
end;
function TFamilyCollectionItem.GetFontIndex(AStyle: string;
NeedAllStyles: boolean; NoMoreStyle: boolean): integer;
begin
result := GetFontIndexByStyles(AStyle); //exact match
if result = -1 then
result := GetFontIndex(StylesToArray(AStyle),NeedAllStyles,NoMoreStyle);
end;
function TFamilyCollectionItem.GetFont(AStyle: string; NeedAllStyles: boolean; NoMoreStyle: boolean): TCustomFontCollectionItem;
begin
result := GetFontByStyles(AStyle); //exact match
if result = nil then
result := GetFont(StylesToArray(AStyle),NeedAllStyles,NoMoreStyle);
end;
function TFamilyCollectionItem.HasStyle(AName: string): boolean;
var i: integer;
begin
for i := 0 to FStyleCount-1 do
if CompareText(FStyles[i],AName)=0 then
begin
result := true;
exit;
end;
result := false;
end;
{ TFontCollection }
function TFreeTypeFontCollection.GetFontCount: integer;
begin
result := FFontList.Count;
end;
function TFreeTypeFontCollection.GetFamilyCount: integer;
begin
result := FFamilyList.Count;
end;
function TFreeTypeFontCollection.FindFont(AFileName: string): TFontCollectionItem;
var Comp: integer;
node : TAvgLvlTreeNode;
begin
node:= FFontList.Root;
while (node<>nil) do begin
Comp:=CompareStr(AFileName,TFontCollectionItem(node.Data).Filename);
if Comp=0 then break;
if Comp<0 then begin
node:=node.Left
end else begin
node:=node.Right
end;
end;
if node = nil then
result := nil
else
result := TFontCollectionItem(node.Data);
end;
function TFreeTypeFontCollection.GetFamily(AName: string
): TCustomFamilyCollectionItem;
begin
if AName = '' then
begin
result := GetFamily('Arial');
exit;
end;
result := FindFamily(AName);
if (result = nil) and (CompareText(AName,'Arial')=0) then result := FindFamily('Helvetica');
if (result = nil) and (CompareText(AName,'Helvetica')=0) then result := FindFamily('Arial');
if (result = nil) and (CompareText(AName,'Courier New')=0) then result := FindFamily('Nimbus Monospace');
if (result = nil) and (CompareText(AName,'Courier New')=0) then result := FindFamily('Courier');
if (result = nil) and (CompareText(AName,'Nimbus Monospace')=0) then result := FindFamily('Courier New');
if (result = nil) and (CompareText(AName,'Nimbus Monospace')=0) then result := FindFamily('Courier');
if (result = nil) and (CompareText(AName,'Courier')=0) then result := FindFamily('Courier New');
if (result = nil) and (CompareText(AName,'Courier')=0) then result := FindFamily('Nimbus Monospace');
if (result = nil) and (CompareText(AName,'Times')=0) then result := FindFamily('Times New Roman');
if (result = nil) and (CompareText(AName,'Times')=0) then result := FindFamily('CG Times');
if (result = nil) and (CompareText(AName,'Times New Roman')=0) then result := FindFamily('Times');
if (result = nil) and (CompareText(AName,'Times New Roman')=0) then result := FindFamily('CG Times');
if (result = nil) and (CompareText(AName,'CG Times')=0) then result := FindFamily('Times');
if (result = nil) and (CompareText(AName,'CG Times')=0) then result := FindFamily('Times New Roman');
end;
function TFreeTypeFontCollection.AddFamily(AName: string): TFamilyCollectionItem;
var
f: TFamilyCollectionItem;
begin
f := FindFamily(AName);
if f = nil then
begin
result := TFamilyCollectionItem.Create(AName);
FFamilyList.Add(result);
end else
result := f;
end;
function TFreeTypeFontCollection.FindFamily(AName: string): TFamilyCollectionItem;
var Comp: integer;
node : TAvgLvlTreeNode;
begin
node:= FFamilyList.Root;
while (node<>nil) do begin
Comp:=CompareText(AName,TFamilyCollectionItem(node.Data).FamilyName);
if Comp=0 then break;
if Comp<0 then begin
node:=node.Left
end else begin
node:=node.Right
end;
end;
if node = nil then
result := nil
else
result := TFamilyCollectionItem(node.Data);
end;
function TFreeTypeFontCollection.CompareFontFileName(Tree: TAvgLvlTree; Data1,
Data2: Pointer): integer;
begin
result := CompareStr(TFontCollectionItem(Data1).Filename,TFontCollectionItem(Data2).Filename);
end;
function TFreeTypeFontCollection.CompareFamilyName(Tree: TAvgLvlTree; Data1,
Data2: Pointer): integer;
begin
result := CompareText(TFamilyCollectionItem(Data1).FamilyName,TFamilyCollectionItem(Data2).FamilyName);
end;
function TFreeTypeFontCollection.GetFont(AFileName: string
): TCustomFontCollectionItem;
begin
result := FindFont(AFilename);
end;
constructor TFreeTypeFontCollection.Create;
begin
FUpdateCount := 0;
FTempFont := nil;
FFontList := TAvgLvlTree.CreateObjectCompare(@CompareFontFileName);
FFamilyList := TAvgLvlTree.CreateObjectCompare(@CompareFamilyName);
end;
procedure TFreeTypeFontCollection.Clear;
begin
FFamilyList.FreeAndClear;
FFontList.FreeAndClear;
end;
procedure TFreeTypeFontCollection.BeginUpdate;
begin
if (FUpdateCount = 0) and (FTempFont = nil) then
FTempFont := TFreeTypeFont.Create;
inc(FUpdateCount);
end;
procedure TFreeTypeFontCollection.AddFolder(AFolder: string);
var sr: TSearchRec;
files: TStringList;
i: integer;
begin
if (length(AFolder) <> 0) and (AFolder[length(AFolder)] <> PathDelim) then
AFolder += PathDelim;
files := TStringList.Create;
BeginUpdate;
try
if FindFirst(AFolder+'*.ttf',faAnyfile,sr) = 0 then
repeat
if sr.Attr and (faDirectory+faVolumeId) = 0 then
files.Add(AFolder+sr.Name);
until FindNext(sr) <> 0;
files.Sort;
for i := 0 to files.Count-1 do
AddFile(files[i]);
finally
EndUpdate;
end;
files.Free;
end;
function TFreeTypeFontCollection.AddFile(AFilename: string): boolean;
var info: TFreeTypeInformation;
fName: string;
item: TFontCollectionItem;
f: TFamilyCollectionItem;
begin
result := false;
BeginUpdate;
try
FTempFont.Name := AFilename;
fName := FTempFont.Family;
if fName <> '' then
begin
f := AddFamily(fName);
item := TFontCollectionItem.Create(AFilename);
FFontList.Add(item);
with item do
begin
VersionNumber:= FTempFont.VersionNumber;
for info := low(TFreeTypeInformation) to high(TFreeTypeInformation) do
Information[info] := FTempFont.Information[info];
end;
f.AddFont(item);
result := true;
end;
finally
EndUpdate;
end;
end;
procedure TFreeTypeFontCollection.EndUpdate;
begin
if FUpdateCount > 0 then
begin
dec(FUpdateCount);
if FUpdateCount = 0 then FreeAndNil(FTempFont);
end;
end;
destructor TFreeTypeFontCollection.Destroy;
begin
Clear;
FFontList.Free;
FFamilyList.Free;
FTempFont.Free;
inherited Destroy;
end;
function TFreeTypeFontCollection.FontFileEnumerator: IFreeTypeFontEnumerator;
begin
result := TFontEnumerator.Create(FFontList.GetEnumerator);
end;
function TFreeTypeFontCollection.FamilyEnumerator: IFreeTypeFamilyEnumerator;
begin
result := TFamilyEnumerator.Create(FFamilyList.GetEnumerator);
end;
var
InternalDefaultFontCollection : TFreeTypeFontCollection;
initialization
InternalDefaultFontCollection := TFreeTypeFontCollection.Create;
FontCollection := InternalDefaultFontCollection;
finalization
InternalDefaultFontCollection.Free;
end.