mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-01 11:04:15 +02:00
817 lines
22 KiB
ObjectPascal
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.
|
|
|