summaryrefslogtreecommitdiff
path: root/src/corelib/render
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graemeg@gmail.com>2014-08-20 02:11:13 +0100
committerGraeme Geldenhuys <graemeg@gmail.com>2014-08-20 02:11:13 +0100
commitc8acc2c1666015daeb3038c838e5018c0ecd8903 (patch)
tree5ad2edaf0e5fb6be146491226dca4d915333d80d /src/corelib/render
parentc45010b6370b50f8e6192ddb7dc3d7762c8c29f7 (diff)
parentd0d8573b046e5020d05c86a970d303084de19b7d (diff)
downloadfpGUI-c8acc2c1666015daeb3038c838e5018c0ecd8903.tar.xz
Merge branch 'release-1.2' into master
Diffstat (limited to 'src/corelib/render')
-rw-r--r--src/corelib/render/software/Agg2D.pas66
-rw-r--r--src/corelib/render/software/agg-demos/Agg2DConsole.dpr148
-rw-r--r--src/corelib/render/software/agg_2D.pas24
-rw-r--r--src/corelib/render/software/agg_basics.pas4
-rw-r--r--src/corelib/render/software/agg_platform_x11.inc83
-rw-r--r--src/corelib/render/software/agg_renderer_base.pas12
-rw-r--r--src/corelib/render/software/fpg_fontcache.pas347
-rw-r--r--src/corelib/render/software/platform/mac/agg_platform_support.pas4
8 files changed, 666 insertions, 22 deletions
diff --git a/src/corelib/render/software/Agg2D.pas b/src/corelib/render/software/Agg2D.pas
index 50a68fb8..229294d2 100644
--- a/src/corelib/render/software/Agg2D.pas
+++ b/src/corelib/render/software/Agg2D.pas
@@ -400,6 +400,8 @@ type
procedure ClearAll(c : TAggColor ); overload;
procedure ClearAll(r ,g ,b : byte; a : byte = 255 ); overload;
+ procedure FillAll(c: TAggColor); overload;
+ procedure FillAll(r, g, b: byte; a: byte = 255); overload;
// Master Rendering Properties
procedure BlendMode(m : TAggBlendMode ); overload;
@@ -1288,6 +1290,9 @@ begin
m_pathTransform.Construct (@m_convCurve ,@m_transform );
m_strokeTransform.Construct(@m_convStroke ,@m_transform );
+ m_convDash.remove_all_dashes;
+ m_convDash.add_dash(600, 0); {$NOTE Find a better way to prevent dash generation }
+
{$IFDEF AGG2D_USE_FREETYPE }
m_fontEngine.Construct;
{$ENDIF }
@@ -1491,6 +1496,22 @@ begin
end;
+procedure TAgg2D.FillAll(c: TAggColor);
+var
+ clr: aggclr;
+begin
+ clr.Construct (c );
+ m_renBase.fill(@clr );
+end;
+
+procedure TAgg2D.FillAll(r, g, b: byte; a: byte);
+var
+ clr: TAggColor;
+begin
+ clr.Construct(r, g, b, a);
+ FillAll(clr);
+end;
+
{ CLEARCLIPBOX }
procedure TAgg2D.ClearClipBox(c : TAggColor );
var
@@ -1517,14 +1538,14 @@ end;
{ WORLDTOSCREEN }
procedure TAgg2D.WorldToScreen(x ,y : PDouble );
begin
- m_transform.transform(@m_transform ,double_ptr(x ) ,double_ptr(y ) );
+ m_transform.transform(@m_transform, x, y);
end;
{ SCREENTOWORLD }
procedure TAgg2D.ScreenToWorld(x ,y : PDouble );
begin
- m_transform.inverse_transform(@m_transform ,double_ptr(x ) ,double_ptr(y ) );
+ m_transform.inverse_transform(@m_transform, x, y);
end;
@@ -2649,7 +2670,8 @@ begin
m_fontEngine.hinting_(m_textHints );
if cache = AGG_VectorFontCache then
- m_fontEngine.height_(height )
+ {$NOTE We need to fix this. Translating from font pt to pixels is inaccurate. This is just a temp fix for now. }
+ m_fontEngine.height_(height * 1.3333 ) // 9pt = ~12px so that is a ratio of 1.3333
else
m_fontEngine.height_(worldToScreen(height ) );
{$ENDIF}
@@ -3534,18 +3556,29 @@ begin
end;
procedure TAgg2D.DoSetFontRes(fntres: TfpgFontResourceBase);
+{$IFDEF WINDOWS}
begin
- {$NOTE This is only temporary until I can correctly query font names }
- {$IFDEF WINDOWS}
+ {$IFDEF AGG2D_USE_FREETYPE }
+ Font('c:\WINNT\Fonts\arial.ttf', 10);
+ {$ENDIF }
+ {$IFDEF AGG2D_USE_WINFONTS}
Font('Arial', 13);
- {$ELSE}
- {$IFDEF BSD}
- Font('/usr/local/lib/X11/fonts/Liberation/LiberationSans-Regular.ttf', 13);
- {$ELSE}
- Font('/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Regular.ttf', 13);
- {$ENDIF}
- {$ENDIF}
+ {$ENDIF }
end;
+{$ENDIF}
+{$IFDEF UNIX}
+var
+ s: TfpgString;
+ i: integer;
+ fnt: TFontCacheItem;
+ lSize: double;
+begin
+ fnt := FontCacheItemFromFontDesc(TfpgFontResource(fntres).FontDesc, lSize);
+ i := gFontCache.Find(fnt);
+ if i > 0 then
+ Font(gFontCache.Items[i].FileName, lSize, fnt.IsBold, fnt.IsItalic, AGG_VectorFontCache, Deg2Rad(fnt.Angle));
+end;
+{$ENDIF}
procedure TAgg2D.DoSetTextColor(cl: TfpgColor);
var
@@ -3555,7 +3588,7 @@ begin
c := fpgColorToRGB(cl);
t := fpgColorToRGBTriple(c);
- FillColor(t.Red, t.Green, t.Blue{, t.Alpha});
+ FillColor(t.Red, t.Green, t.Blue, t.Alpha);
end;
procedure TAgg2D.DoSetColor(cl: TfpgColor);
@@ -3566,7 +3599,7 @@ begin
c := fpgColorToRGB(cl);
t := fpgColorToRGBTriple(c);
- LineColor(t.Red, t.Green, t.Blue{, t.Alpha});
+ LineColor(t.Red, t.Green, t.Blue, t.Alpha);
end;
procedure TAgg2D.DoSetLineStyle(awidth: integer; astyle: TfpgLineStyle);
@@ -3635,7 +3668,10 @@ end;
procedure TAgg2D.DoFillTriangle(x1, y1, x2, y2, x3, y3: TfpgCoord);
begin
-
+ LineWidth(1);
+ FillColor(LineColor);
+ LineColor(LineColor);
+ Triangle(x1+0.5, y1+0.5, x2+0.5, y2+0.5, x3+0.5, y3+0.5);
end;
procedure TAgg2D.DoDrawRectangle(x, y, w, h: TfpgCoord);
diff --git a/src/corelib/render/software/agg-demos/Agg2DConsole.dpr b/src/corelib/render/software/agg-demos/Agg2DConsole.dpr
new file mode 100644
index 00000000..bc8badbc
--- /dev/null
+++ b/src/corelib/render/software/agg-demos/Agg2DConsole.dpr
@@ -0,0 +1,148 @@
+{
+ This is a console application demo. It uses the Agg2D object,
+ which has a much friendlier API, to do all the drawing. We then
+ save the image buffer to a JPG, using the fcl-image package,
+ which comes standard with the Free Pascal Compiler.
+
+// Paths: ..\;..\svg;..\util;expat-wrap
+}
+program console_aggpas_2;
+
+{$mode objfpc}{$H+}
+
+uses
+ sysutils,
+ FPimage,
+ FPWriteJPEG,
+ agg_2D,
+ agg_basics;
+
+const
+ ImageWidth = 800;
+ ImageHeight = 480;
+ RGBA_Width = 4;
+ LineCount = 30;
+ {$IFDEF Unix}
+ FontFile = '../../arial.ttf';
+ {$ENDIF}
+ {$IFDEF Windows}
+ FontFile = 'Arial';
+ {$ENDIF}
+
+type
+ TPainter = class(TObject)
+ public
+ procedure HandlePlug;
+ procedure DrawStuff(agg: Agg2D_ptr);
+ end;
+
+
+procedure TPainter.HandlePlug;
+var
+ agg: Agg2D_ptr;
+ buf: array of int8;
+ image: TFPMemoryImage;
+ writer: TFPWriterJPEG;
+ x, y: Integer;
+ c: TFPColor;
+ time, totalTime: TDateTime;
+ function getBufItemAsWord(aDelta: byte): Word;
+ var
+ actualY: Integer;
+ begin
+ actualY := ImageHeight - y - 1;
+ result :=
+ Word(buf[x * RGBA_Width + actualY * ImageWidth * RGBA_Width + aDelta] shl 8)
+ or Word(128);
+ end;
+begin
+ totalTime := Now;
+ time := Now;
+ SetLength(buf, ImageWidth * ImageHeight * RGBA_Width);
+ New(agg, Construct);
+ agg^.attach(@(buf[0]), ImageWidth, ImageHeight, ImageWidth * RGBA_Width);
+ DrawStuff(agg);
+ Dispose(agg, Destruct); // not necessary to keep it after rendering is finished
+ time := Now - time;
+// Logger.Emit('Draw: time spent: ' + TimeStampToString(time));
+ time := Now;
+ image := TFPMemoryImage.create(ImageWidth, ImageHeight);
+ for x := 0 to ImageWidth - 1 do
+ for y := 0 to ImageHeight - 1 do
+ begin
+ c.red := getBufItemAsWord(2);
+ c.green := getBufItemAsWord(1);
+ c.blue := getBufItemAsWord(0);
+ c.alpha := getBufItemAsWord(3);
+ image.Colors[x, y] := c;
+ end;
+ time := Now - time;
+// WriteLn('Image copy: time spent: ' + DateTimeToString(time));
+ time := Now;
+ writer := TFPWriterJPEG.Create;
+ writer.CompressionQuality := $FF div 3; // bad quality plz
+ writer.ProgressiveEncoding := True;
+ image.SaveToFile('test.jpeg', writer);
+ image.Free;
+ writer.Free;
+ time := Now - time;
+// WriteLn('Image encode: time spent: ' + DateTimeToString(time));
+ totalTime := Now - totalTime;
+// WriteLn('Total time: ' + DateTimeToString(totalTime));
+end;
+
+procedure TPainter.DrawStuff(agg: Agg2D_ptr);
+var
+ i: Integer;
+ x, y, px, py, d: Double;
+begin
+ agg^.clearAll(0, 0, 0);
+ agg^.lineColor(0, 0, 0, 255);
+ agg^.lineWidth(3);
+ agg^.rectangle(0, 0, ImageWidth, ImageHeight);
+ agg^.font(fontfile, 16);
+ d := ImageWidth / LineCount;
+ agg^.lineColor(0, 0, 0, 100);
+ agg^.lineWidth(1);
+ for i := 1 to LineCount - 1 do
+ begin
+ x := i * d;
+ agg^.line(x, 0, x, ImageHeight);
+ end;
+ for i := 1 to trunc(ImageHeight / d) do
+ begin
+ y := i * d;
+ agg^.line(0, y, ImageWidth, y);
+ end;
+ x := 0;
+ y := ImageHeight / 2;
+ px := x;
+ py := y;
+ agg^.lineColor(255, 0, 0, 200);
+ agg^.fillColor(0, 0, 0, 200);
+ agg^.lineWidth(3);
+ for i := 0 to LineCount - 1 do
+ begin
+ x := x + d;
+ y := y + Random(Round(ImageHeight / 3)) - ImageHeight / 6;
+ if y < 0 then
+ y := ImageHeight / 6;
+ if y >= ImageHeight then
+ y := ImageHeight - ImageHeight / 6;
+ agg^.line(px, py, x, y);
+ agg^.text(x, y, char_ptr(IntToStr(i) + ' point'{' шта?'}));
+ px := x;
+ py := y;
+ end;
+end;
+
+
+var
+ p: TPainter;
+begin
+ Randomize;
+ p := TPainter.Create;
+ p.HandlePlug;
+ p.Free;
+end.
+
diff --git a/src/corelib/render/software/agg_2D.pas b/src/corelib/render/software/agg_2D.pas
index a6296e2c..45d88e44 100644
--- a/src/corelib/render/software/agg_2D.pas
+++ b/src/corelib/render/software/agg_2D.pas
@@ -3,11 +3,11 @@
// Based on Anti-Grain Geometry
// Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com)
//
-// Agg2D - Version 1.0 Release Milano 3 (AggPas 2.3 RM3)
+// Agg2D - Version 1.0 Release Milano 3 (AggPas 2.4 RM3)
// Pascal Port By: Milan Marusinec alias Milano
// milan@marusinec.sk
// http://www.aggpas.org
-// Copyright (c) 2007
+// Copyright (c) 2007 - 2008
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
@@ -325,6 +325,8 @@ type
procedure clearAll(c : Color ); overload;
procedure clearAll(r ,g ,b : unsigned; a : unsigned = 255 ); overload;
+ procedure FillAll(c: Color); overload;
+ procedure FillAll(r, g, b: byte; a: byte = 255); overload;
procedure clearClipBox(c : Color ); overload;
procedure clearClipBox(r ,g ,b : unsigned; a : unsigned = 255 ); overload;
@@ -424,7 +426,7 @@ type
rxTop ,ryTop : double ); overload;
procedure ellipse(cx ,cy ,rx ,ry : double );
-
+
procedure arc (cx ,cy ,rx ,ry ,start ,sweep : double );
procedure star(cx ,cy ,r1 ,r2 ,startAngle : double; numRays : int );
@@ -932,6 +934,22 @@ begin
end;
+procedure Agg2D.FillAll(c: Color);
+var
+ clr: aggclr;
+begin
+ clr.Construct (c );
+ m_renBase.fill(@clr );
+end;
+
+procedure Agg2D.FillAll(r, g, b: byte; a: byte);
+var
+ clr: Color;
+begin
+ clr.Construct(r, g, b, a);
+ FillAll(clr);
+end;
+
{ CLEARCLIPBOX }
procedure Agg2D.clearClipBox(c : Color );
var
diff --git a/src/corelib/render/software/agg_basics.pas b/src/corelib/render/software/agg_basics.pas
index cc116cfe..56eb6fba 100644
--- a/src/corelib/render/software/agg_basics.pas
+++ b/src/corelib/render/software/agg_basics.pas
@@ -357,8 +357,8 @@ type
procedure NoP;
{ These implementations have changed to use FPC's Sar*() functions, so should
- now support all platforms with ASM code. At a later date these functions
- could be removed completely. }
+ now support all platforms without the need for ASM code. At a later date these
+ functions could be removed completely. }
function shr_int8 (i ,shift : int8 ) : int8; inline;
function shr_int16(i ,shift : int16 ) : int16; inline;
function shr_int32(i ,shift : int ) : int; inline;
diff --git a/src/corelib/render/software/agg_platform_x11.inc b/src/corelib/render/software/agg_platform_x11.inc
index 331b572e..dc5556fa 100644
--- a/src/corelib/render/software/agg_platform_x11.inc
+++ b/src/corelib/render/software/agg_platform_x11.inc
@@ -18,6 +18,7 @@
{$ifdef uses_implementation}
fpg_x11,
+ fpg_fontcache,
{$endif}
@@ -27,6 +28,88 @@ type
// to get access to protected methods (seeing that FPC doesn't support Friend-classes)
TImageHack = class(TfpgImage);
+function FontCacheItemFromFontDesc(const desc: string; var asize: double): TFontCacheItem;
+var
+ facename: string;
+ cp: integer;
+ c: char;
+ token: string;
+ prop, propval: string;
+
+ function NextC: char;
+ begin
+ Inc(cp);
+ if cp > length(desc) then
+ c := #0
+ else
+ c := desc[cp];
+ Result := c;
+ end;
+
+ procedure NextToken;
+ begin
+ token := '';
+ while (c <> #0) and (c in [' ', 'a'..'z', 'A'..'Z', '_', '0'..'9', '.']) do
+ begin
+ token := token + c;
+ NextC;
+ end;
+ end;
+
+begin
+ Result := TFontCacheItem.Create('');
+
+ cp := 0;
+ NextC;
+ NextToken;
+
+ facename := token;
+ // Add known substites
+ if lowercase(facename) = 'times' then
+ facename := 'Times New Roman'
+ else if lowercase(facename) = 'courier' then
+ facename := 'Courier New'
+ else if lowercase(facename) = 'monospace' then
+ facename := 'Courier New';
+ Result.FamilyName := facename;
+
+ if c = '-' then
+ begin
+ NextC;
+ NextToken;
+ asize := StrToIntDef(token, 0);
+ end;
+
+ while c = ':' do
+ begin
+ NextC;
+ NextToken;
+
+ prop := UpperCase(token);
+ propval := '';
+
+ if c = '=' then
+ begin
+ NextC;
+ NextToken;
+ propval := UpperCase(token);
+ end;
+
+ if prop = 'BOLD' then
+ Result.IsBold := True
+ else if prop = 'ITALIC' then
+ Result.IsItalic := True
+ else if prop = 'ANGLE' then
+ Result.Angle := StrToFloatDef(propval, 0.0);
+// else if prop = 'ANTIALIAS' then
+// if propval = 'FALSE' then
+// lf.lfQuality := NONANTIALIASED_QUALITY else
+// if propval = 'DEFAULT' then
+// lf.lfQuality := DEFAULT_QUALITY;
+ end;
+end;
+
+
procedure TAgg2D.DoPutBufferToScreen(x, y, w, h: TfpgCoord);
var
drawgc: Tgc;
diff --git a/src/corelib/render/software/agg_renderer_base.pas b/src/corelib/render/software/agg_renderer_base.pas
index 926aebd5..cc2bade4 100644
--- a/src/corelib/render/software/agg_renderer_base.pas
+++ b/src/corelib/render/software/agg_renderer_base.pas
@@ -79,6 +79,7 @@ type
function bounding_ymax : int; virtual;
procedure clear(c : aggclr_ptr );
+ procedure fill(const c: aggclr_ptr);
procedure copy_pixel (x ,y : int; c : aggclr_ptr ); virtual;
procedure blend_pixel(x ,y : int; c : aggclr_ptr; cover : int8u ); virtual;
@@ -348,6 +349,17 @@ begin
end;
+procedure renderer_base.fill(const c: aggclr_ptr);
+var
+ y: unsigned;
+begin
+ if (width > 0) and (height > 0) then
+ begin
+ for y:=0 to height - 1 do
+ m_ren.blend_hline(m_ren, 0, y, width, c, cover_mask);
+ end;
+end;
+
{ COPY_PIXEL }
procedure renderer_base.copy_pixel(x, y: int; c: aggclr_ptr);
begin
diff --git a/src/corelib/render/software/fpg_fontcache.pas b/src/corelib/render/software/fpg_fontcache.pas
new file mode 100644
index 00000000..15f65e40
--- /dev/null
+++ b/src/corelib/render/software/fpg_fontcache.pas
@@ -0,0 +1,347 @@
+{
+ fpGUI - Free Pascal GUI Toolkit
+
+ Copyright (C) 2006 - 2013 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Description:
+ This is a homegrown font cache, or font translation system. AggPas
+ references font files (eg: *.ttf) directly, whereas the rest
+ of fpGUI doesn't. Under X11 for example, the translation of
+ 'Aria-12' to the actual *.ttf file will be done by the fontconfig
+ library. Unfortunately fontconfig doesn't have an API to give
+ use that *.ttf font file it resolved too. So for AggPas (or rather
+ the AggPas backend in fpGUI) we had to implement our own
+ font translation system.
+}
+
+unit fpg_fontcache;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, contnrs, fpg_base;
+
+type
+ TFontCacheItem = class(TObject)
+ private
+ FAngle: double;
+ FFamilyName: TfpgString;
+ FFileName: TfpgString;
+ FFixedWidth: boolean;
+ FStyleFlags: Integer;
+ function GetIsBold: boolean;
+ function GetIsFixedWidth: boolean;
+ function GetIsItalic: boolean;
+ function GetIsRegular: boolean;
+ procedure SetIsBold(AValue: boolean);
+ procedure SetIsFixedWidth(AValue: boolean);
+ procedure SetIsItalic(AValue: boolean);
+ procedure SetIsRegular(AValue: boolean);
+ public
+ constructor Create(const AFilename: TfpgString);
+ property FileName: TfpgString read FFileName write FFileName;
+ property FamilyName: TfpgString read FFamilyName write FFamilyName;
+ property StyleFlags: Integer read FStyleFlags write FStyleFlags;
+ property IsFixedWidth: boolean read GetIsFixedWidth write SetIsFixedWidth;
+ property IsRegular: boolean read GetIsRegular write SetIsRegular;
+ property IsItalic: boolean read GetIsItalic write SetIsItalic;
+ property IsBold: boolean read GetIsBold write SetIsBold;
+ { following properties are used by FontCacheItemFromFontDesc() only }
+ property Angle: double read FAngle write FAngle;
+ end;
+
+
+ TFontCacheList = class(TObject)
+ private
+ FList: TObjectList;
+ procedure SearchForFont(const AFontPath: TfpgString);
+ function BuildFontCacheItem(const AFontFile: TfpgString): TFontCacheItem;
+ procedure SetStyleIfExists(var AText: Ansistring; var AStyleFlags: integer; const AStyleName: AnsiString; const AStyleBit: integer);
+ protected
+ function GetCount: integer; virtual;
+ function GetItem(AIndex: Integer): TFontCacheItem; virtual;
+ procedure SetItem(AIndex: Integer; AValue: TFontCacheItem); virtual;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ procedure BuildFontCache;
+ function Add(const AObject: TFontCacheItem): integer;
+ procedure Clear;
+ property Count: integer read GetCount;
+ function IndexOf(const AObject: TFontCacheItem): integer;
+ function Find(const AFontCacheItem: TFontCacheItem): integer;
+ property Items[AIndex: Integer]: TFontCacheItem read GetItem write SetItem; default;
+ end;
+
+
+function gFontCache: TFontCacheList;
+
+implementation
+
+uses
+ fpg_utils,
+ agg_font_freetype_lib;
+
+const
+ FPG_FONT_STYLE_REGULAR = 1 shl 0; { Regular, Plain, Book }
+ FPG_FONT_STYLE_ITALIC = 1 shl 1; { Itelic }
+ FPG_FONT_STYLE_BOLD = 1 shl 2; { Bold }
+ FPG_FONT_STYLE_CONDENSED = 1 shl 3; { Condensed }
+ FPG_FONT_STYLE_EXTRALIGHT = 1 shl 4; { ExtraLight }
+ FPG_FONT_STYLE_LIGHT = 1 shl 5; { Light }
+ FPG_FONT_STYLE_SEMIBOLD = 1 shl 6; { Semibold }
+ FPG_FONT_STYLE_MEDIUM = 1 shl 7; { Medium }
+ FPG_FONT_STYLE_BLACK = 1 shl 8; { Black }
+ FPG_FONT_STYLE_FIXEDWIDTH = 1 shl 9; { Fixedwidth }
+
+var
+ m_library: FT_Library_ptr;
+ uFontCacheList: TFontCacheList;
+
+function gFontCache: TFontCacheList;
+begin
+ if not Assigned(uFontCacheList) then
+ begin
+ uFontCacheList := TFontCacheList.Create;
+ uFontCacheList.BuildFontCache;
+ end;
+ Result := uFontCacheList;
+end;
+
+{ TFontCacheItem }
+
+function TFontCacheItem.GetIsBold: boolean;
+begin
+ Result := (FStyleFlags and FPG_FONT_STYLE_BOLD) <> 0;
+end;
+
+function TFontCacheItem.GetIsFixedWidth: boolean;
+begin
+ Result := (FStyleFlags and FPG_FONT_STYLE_FIXEDWIDTH) <> 0;
+end;
+
+function TFontCacheItem.GetIsItalic: boolean;
+begin
+ Result := (FStyleFlags and FPG_FONT_STYLE_ITALIC) <> 0;
+end;
+
+function TFontCacheItem.GetIsRegular: boolean;
+begin
+ Result := (FStyleFlags and FPG_FONT_STYLE_REGULAR) <> 0;
+end;
+
+procedure TFontCacheItem.SetIsBold(AValue: boolean);
+begin
+ FStyleFlags := FStyleFlags or FPG_FONT_STYLE_BOLD;
+end;
+
+procedure TFontCacheItem.SetIsFixedWidth(AValue: boolean);
+begin
+ FStyleFlags := FStyleFlags or FPG_FONT_STYLE_FIXEDWIDTH;
+ FStyleFlags := FStyleFlags and (not FPG_FONT_STYLE_REGULAR);
+end;
+
+procedure TFontCacheItem.SetIsItalic(AValue: boolean);
+begin
+ FStyleFlags := FStyleFlags or FPG_FONT_STYLE_ITALIC;
+end;
+
+procedure TFontCacheItem.SetIsRegular(AValue: boolean);
+begin
+ FStyleFlags := FStyleFlags or FPG_FONT_STYLE_REGULAR;
+ FStyleFlags := FStyleFlags and (not FPG_FONT_STYLE_FIXEDWIDTH);
+end;
+
+constructor TFontCacheItem.Create(const AFilename: TfpgString);
+begin
+ inherited Create;
+ FFileName := AFilename;
+ FStyleFlags := FPG_FONT_STYLE_REGULAR;
+ FAngle := 0.0;
+end;
+
+{ TFontCacheList }
+
+procedure TFontCacheList.SearchForFont(const AFontPath: TfpgString);
+var
+ sr: TSearchRec;
+ lFont: TFontCacheItem;
+ s: TfpgString;
+begin
+ // The extra 'or' includes Normal attribute files under Windows. faAnyFile doesn't return those.
+ // Reported to FPC as bug 9440 in Mantis.
+ if fpgFindFirst(AFontPath + AllFilesMask, faAnyFile or $00000080, sr) = 0 then
+ begin
+ repeat
+ // check if special files to skip
+ if (sr.Name = '.') or (sr.Name = '..') or (sr.Name = '') then
+ Continue;
+ // We got something, so lets continue
+ s := fpgFromOSEncoding(sr.Name);
+ if (sr.Attr and faDirectory) <> 0 then // found a directory
+ SearchForFont(fpgAppendPathDelim(AFontPath + s))
+ else
+ begin // we have a file
+ if (lowercase(fpgExtractFileExt(s)) = '.ttf') or
+ (lowercase(fpgExtractFileExt(s)) = '.otf') then
+ begin
+ lFont := BuildFontCacheItem(AFontPath + s);
+ Add(lFont);
+ end;
+ end;
+ until fpgFindNext(sr) <> 0;
+ end;
+end;
+
+function TFontCacheList.BuildFontCacheItem(const AFontFile: TfpgString): TFontCacheItem;
+var
+ face_ptr: FT_Face_ptr;
+ s: Ansistring;
+ i: integer;
+ flags: integer;
+begin
+ FT_New_Face(m_library, PChar(AFontFile), 0, face_ptr);
+ Result := TFontCacheItem.Create(AFontFile);
+ Result.FamilyName := face_ptr^.family_name;
+
+ // extract simple styles first
+// if (face_ptr^.face_flags and FT_FACE_FLAG_FIXED_WIDTH) <> 0 then
+// Result.StyleFlags := FPG_FONT_STYLE_FIXEDWIDTH; // this should overwrite Regular style
+
+ if (face_ptr^.style_flags and FT_STYLE_FLAG_ITALIC) <> 0 then
+ Result.StyleFlags := Result.StyleFlags or FPG_FONT_STYLE_ITALIC;
+
+ if (face_ptr^.style_flags and FT_STYLE_FLAG_BOLD) <> 0 then
+ Result.StyleFlags := Result.StyleFlags or FPG_FONT_STYLE_BOLD;
+
+ // Now to more complex styles stored in StyleName field. eg: 'Condensed Medium'
+ s := face_ptr^.style_name;
+ flags := Result.StyleFlags;
+ SetStyleIfExists(s, flags, 'Condensed', FPG_FONT_STYLE_CONDENSED);
+ SetStyleIfExists(s, flags, 'ExtraLight', FPG_FONT_STYLE_EXTRALIGHT);
+ SetStyleIfExists(s, flags, 'Light', FPG_FONT_STYLE_LIGHT);
+ SetStyleIfExists(s, flags, 'Semibold', FPG_FONT_STYLE_SEMIBOLD);
+ SetStyleIfExists(s, flags, 'Medium', FPG_FONT_STYLE_MEDIUM);
+ SetStyleIfExists(s, flags, 'Black', FPG_FONT_STYLE_BLACK);
+ Result.StyleFlags := flags;
+
+ FT_Done_Face(face_ptr);
+end;
+
+procedure TFontCacheList.SetStyleIfExists(var AText: Ansistring; var AStyleFlags: integer;
+ const AStyleName: AnsiString; const AStyleBit: integer);
+var
+ i: integer;
+begin
+ i := Pos(AStyleName, AText);
+ if i > 0 then
+ begin
+ AStyleFlags := AStyleFlags or AStyleBit;
+ Delete(AText, Length(AStyleName), i);
+ end;
+end;
+
+function TFontCacheList.GetCount: integer;
+begin
+ Result := FList.Count;
+end;
+
+function TFontCacheList.GetItem(AIndex: Integer): TFontCacheItem;
+begin
+ Result := TFontCacheItem(FList.Items[AIndex]);
+end;
+
+procedure TFontCacheList.SetItem(AIndex: Integer; AValue: TFontCacheItem);
+begin
+ FList.Items[AIndex] := AValue;
+end;
+
+constructor TFontCacheList.Create;
+begin
+ inherited Create;
+ FList := TObjectList.Create;
+end;
+
+destructor TFontCacheList.Destroy;
+begin
+ FList.Free;
+ inherited Destroy;
+end;
+
+procedure TFontCacheList.BuildFontCache;
+var
+ lPath: TfpgString;
+ lPathList: TStringList;
+ i: integer;
+begin
+ try
+ m_library := nil;
+ FT_Init_FreeType(m_library);
+
+ lPathList := TStringList.Create;
+ lPathList.Add('/usr/share/cups/fonts/');
+ lPathList.Add('/usr/share/fonts/truetype/');
+ lPathList.Add('/usr/local/lib/X11/fonts/');
+ lPathList.Add(GetUserDir + '.fonts/');
+ for i := 0 to lPathList.Count-1 do
+ begin
+ lPath := lPathList[i];
+ SearchForFont(lPath);
+ end;
+ finally
+ FT_Done_FreeType(m_library);
+ m_library := nil;
+ lPathList.Free;
+ end;
+end;
+
+function TFontCacheList.Add(const AObject: TFontCacheItem): integer;
+begin
+ Result := FList.Add(AObject);
+end;
+
+procedure TFontCacheList.Clear;
+begin
+ FList.Clear;
+end;
+
+function TFontCacheList.IndexOf(const AObject: TFontCacheItem): integer;
+begin
+ Result := FList.IndexOf(AObject);
+end;
+
+function TFontCacheList.Find(const AFontCacheItem: TFontCacheItem): integer;
+var
+ i: integer;
+begin
+ Result := -1; // nothing found
+ for i := 0 to Count-1 do
+ begin
+ if (Items[i].FamilyName = AFontCacheItem.FamilyName) and
+ (Items[i].StyleFlags = AFontCacheItem.StyleFlags) then
+ begin
+ Result := i;
+ exit;
+ end;
+ end;
+end;
+
+
+initialization
+ uFontCacheList := nil;
+
+finalization
+ uFontCacheList.Free;
+
+end.
+
diff --git a/src/corelib/render/software/platform/mac/agg_platform_support.pas b/src/corelib/render/software/platform/mac/agg_platform_support.pas
index 608b7854..e9886b64 100644
--- a/src/corelib/render/software/platform/mac/agg_platform_support.pas
+++ b/src/corelib/render/software/platform/mac/agg_platform_support.pas
@@ -92,10 +92,10 @@ type
// Possible formats of the rendering buffer. Initially I thought that it's
// reasonable to create the buffer and the rendering functions in
// accordance with the native pixel format of the system because it
-// would have no overhead for pixel format conersion.
+// would have no overhead for pixel format conversion.
// But eventually I came to a conclusion that having a possibility to
// convert pixel formats on demand is a good idea. First, it was X11 where
-// there lots of different formats and visuals and it would be great to
+// there are lots of different formats and visuals and it would be great to
// render everything in, say, RGB-24 and display it automatically without
// any additional efforts. The second reason is to have a possibility to
// debug renderers for different pixel formats and colorspaces having only