Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgrasvgshapes.pas

    r494 r521  
    1010
    1111type
     12  TSVGGradient = class;
     13 
     14  { TSVGElementWithGradient }
     15
     16  TSVGElementWithGradient = class(TSVGElement)
     17    private
     18      FGradientElement: TSVGGradient;
     19      FGradientElementDefined: boolean;
     20      FCanvasGradient: IBGRACanvasGradient2D;
     21      function EvaluatePercentage(fu: TFloatWithCSSUnit): single; { fu is a percentage of a number [0.0..1.0] }
     22      function GetGradientElement: TSVGGradient;
     23      procedure ResetGradient;
     24      function FindGradientElement: boolean;
     25    protected
     26      procedure Initialize; override;
     27      procedure AddStopElements(canvas: IBGRACanvasGradient2D);
     28      procedure CreateCanvasLinearGradient(ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
     29        const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
     30      procedure CreateCanvasRadialGradient(ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
     31        const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
     32      procedure ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit); override;
     33    public
     34      procedure InitializeGradient(ACanvas2d: TBGRACanvas2D;
     35                const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
     36      property GradientElement: TSVGGradient read GetGradientElement;
     37  end;       
     38 
    1239  { TSVGLine }
    1340
     
    2552      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    2653    public
    27       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     54      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    2855      property x1: TFloatWithCSSUnit read GetX1 write SetX1;
    2956      property y1: TFloatWithCSSUnit read GetY1 write SetY1;
     
    3461  { TSVGRectangle }
    3562
    36   TSVGRectangle = class(TSVGElement)
     63  TSVGRectangle = class(TSVGElementWithGradient)
    3764    private
    3865      function GetX: TFloatWithCSSUnit;
     
    5178      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    5279    public
    53       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     80      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    5481      property x: TFloatWithCSSUnit read GetX write SetX;
    5582      property y: TFloatWithCSSUnit read GetY write SetY;
     
    6289  { TSVGCircle }
    6390
    64   TSVGCircle = class(TSVGElement)
     91  TSVGCircle = class(TSVGElementWithGradient)
    6592    private
    6693      function GetCX: TFloatWithCSSUnit;
     
    73100      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    74101    public
    75       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     102      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    76103      property cx: TFloatWithCSSUnit read GetCX write SetCX;
    77104      property cy: TFloatWithCSSUnit read GetCY write SetCY;
     
    81108  { TSVGEllipse }
    82109
    83   TSVGEllipse = class(TSVGElement)
     110  TSVGEllipse = class(TSVGElementWithGradient)
    84111    private
    85112      function GetCX: TFloatWithCSSUnit;
     
    94121      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    95122    public
    96       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     123      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    97124      property cx: TFloatWithCSSUnit read GetCX write SetCX;
    98125      property cy: TFloatWithCSSUnit read GetCY write SetCY;
     
    103130  { TSVGPath }
    104131
    105   TSVGPath = class(TSVGElement)
     132  TSVGPath = class(TSVGElementWithGradient)
    106133    private
    107134      FPath: TBGRAPath;
     135      FBoundingBox: TRectF;
     136      FBoundingBoxComputed: boolean;
     137      function GetBoundingBoxF: TRectF;
    108138      function GetPath: TBGRAPath;
    109139      function GetPathLength: TFloatWithCSSUnit;
     
    115145      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    116146    public
    117       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
    118       constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter); override;
     147      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
     148      constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    119149      destructor Destroy; override;
    120150      property d: string read GetData write SetData;
    121151      property path: TBGRAPath read GetPath;
    122152      property pathLength: TFloatWithCSSUnit read GetPathLength write SetPathLength;
     153      property boundingBoxF: TRectF read GetBoundingBoxF;
    123154  end;
    124155
    125156  { TSVGPolypoints }
    126157
    127   TSVGPolypoints = class(TSVGElement)
     158  TSVGPolypoints = class(TSVGElementWithGradient)
    128159    private
     160      FBoundingBox: TRectF;
     161      FBoundingBoxComputed: boolean;
     162      function GetBoundingBoxF: TRectF;
    129163      function GetClosed: boolean;
    130164      function GetPoints: string;
     
    132166      procedure SetPoints(AValue: string);
    133167      procedure SetPointsF(AValue: ArrayOfTPointF);
     168      procedure ComputeBoundingBox(APoints: ArrayOfTPointF);
    134169    protected
    135170      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    136171    public
    137       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean); overload;
     172      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink); overload;
    138173      destructor Destroy; override;
    139174      property points: string read GetPoints write SetPoints;
    140175      property pointsF: ArrayOfTPointF read GetPointsF write SetPointsF;
    141176      property closed: boolean read GetClosed;
     177      property boundingBoxF: TRectF read GetBoundingBoxF;
    142178  end;
    143179
    144180  { TSVGText }
    145181
    146   TSVGText = class(TSVGElement)
     182  TSVGText = class(TSVGElementWithGradient)
    147183    private
    148184      function GetFontBold: boolean;
     
    169205      procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    170206    public
    171       constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     207      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    172208      property x: TFloatWithCSSUnit read GetX write SetX;
    173209      property y: TFloatWithCSSUnit read GetY write SetY;
     
    183219
    184220  TSVGContent = class;
     221 
     222  TConvMethod = (cmNone,cmHoriz,cmVertical,cmOrtho);
     223 
     224  { TSVGGradient }
     225
     226  TSVGGradient = class(TSVGElement)
     227    private
     228      FContent: TSVGContent;
     229      function GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
     230      function GetGradientTransform: string;
     231      function GetGradientUnits: string;
     232      function GetHRef: string;
     233      function GetUseObjectBoundingBox: boolean;
     234      procedure SetGradientTransform(AValue: string);
     235      procedure SetGradientUnits(AValue: string);
     236      procedure SetHRef(AValue: string);
     237      function HRefToGradientID(const AValue: string): string;
     238      function FindGradientRef(const AGradientID: string): integer;
     239    protected
     240      InheritedGradients: TSVGElementList;//(for HRef)
     241      procedure Initialize; override;
     242      function GetInheritedAttribute(AValue: string;
     243        AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
     244    public
     245      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     246        ADataLink: TSVGDataLink); override;
     247      constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
     248        AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
     249      destructor Destroy; override;
     250      procedure Recompute; override;
     251      procedure ScanInheritedGradients(const forceScan: boolean = false);
     252      property Content: TSVGContent read FContent;
     253      property hRef: string read GetHRef write SetHRef;
     254      property gradientUnits: string read GetGradientUnits write SetGradientUnits;
     255      property gradientTransform: string read GetGradientTransform write SetGradientTransform;
     256      property useObjectBoundingBox: boolean read GetUseObjectBoundingBox;
     257      property gradientMatrix[AUnit: TCSSUnit]: TAffineMatrix read GetGradientMatrix;
     258  end;       
     259
     260  { TSVGGradientLinear }
     261
     262  TSVGLinearGradient = class(TSVGGradient)
     263    private
     264      function GetX1: TFloatWithCSSUnit;
     265      function GetX2: TFloatWithCSSUnit;
     266      function GetY1: TFloatWithCSSUnit;
     267      function GetY2: TFloatWithCSSUnit;
     268      procedure SetX1(AValue: TFloatWithCSSUnit);
     269      procedure SetX2(AValue: TFloatWithCSSUnit);
     270      procedure SetY1(AValue: TFloatWithCSSUnit);
     271      procedure SetY2(AValue: TFloatWithCSSUnit);
     272    public
     273      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     274        ADataLink: TSVGDataLink); override;
     275      property x1: TFloatWithCSSUnit read GetX1 write SetX1;
     276      property y1: TFloatWithCSSUnit read GetY1 write SetY1;
     277      property x2: TFloatWithCSSUnit read GetX2 write SetX2;
     278      property y2: TFloatWithCSSUnit read GetY2 write SetY2;
     279  end;
     280
     281  { TSVGRadialGradient }
     282
     283  TSVGRadialGradient = class(TSVGGradient)
     284    private
     285      function GetCX: TFloatWithCSSUnit;
     286      function GetCY: TFloatWithCSSUnit;
     287      function GetR: TFloatWithCSSUnit;
     288      function GetFX: TFloatWithCSSUnit;
     289      function GetFY: TFloatWithCSSUnit;
     290      function GetFR: TFloatWithCSSUnit;
     291      procedure SetCX(AValue: TFloatWithCSSUnit);
     292      procedure SetCY(AValue: TFloatWithCSSUnit);
     293      procedure SetR(AValue: TFloatWithCSSUnit);
     294      procedure SetFX(AValue: TFloatWithCSSUnit);
     295      procedure SetFY(AValue: TFloatWithCSSUnit);
     296      procedure SetFR(AValue: TFloatWithCSSUnit);
     297    public
     298      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     299        ADataLink: TSVGDataLink); override;
     300      property cx: TFloatWithCSSUnit read GetCX write SetCX;
     301      property cy: TFloatWithCSSUnit read GetCY write SetCY;
     302      property r: TFloatWithCSSUnit read GetR write SetR;
     303      property fx: TFloatWithCSSUnit read GetFX write SetFX;
     304      property fy: TFloatWithCSSUnit read GetFY write SetFY;
     305      property fr: TFloatWithCSSUnit read GetFR write SetFR;
     306  end;
     307
     308  { TSVGStopGradient }
     309
     310  TSVGStopGradient = class(TSVGElement)
     311    private
     312      function GetOffset: TFloatWithCSSUnit;
     313      procedure SetOffset(AValue: TFloatWithCSSUnit);
     314    public
     315      constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     316        ADataLink: TSVGDataLink); override;
     317      property Offset: TFloatWithCSSUnit read GetOffset write SetOffset;
     318  end;
     319
     320  { TSVGDefine }
     321
     322  TSVGDefine = class(TSVGElement)
     323  protected
     324    FContent: TSVGContent;
     325  public
     326    constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     327      ADataLink: TSVGDataLink); override;
     328    constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
     329      AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
     330    destructor Destroy; override;
     331    procedure Recompute; override;
     332    property Content: TSVGContent read FContent;
     333  end;
    185334
    186335  { TSVGGroup }
     
    191340    procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
    192341  public
    193     constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); override;
     342    constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    194343    constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
    195       AUnits: TCSSUnitConverter); override;
     344      AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
    196345    destructor Destroy; override;
     346    procedure Recompute; override;
    197347    property Content: TSVGContent read FContent;
    198348  end;
     349 
     350  { TSVGStyle }
     351
     352  TSVGStyleItem = record
     353    name,
     354    attribute: string;
     355  end;
     356  ArrayOfTSVGStyleItem = array of TSVGStyleItem;
     357
     358  TSVGStyle = class(TSVGElement)
     359   private
     360     FStyles: ArrayOfTSVGStyleItem;
     361     procedure Parse(const s: String);
     362     function IsValidID(const sid: integer): boolean;
     363     function GetStyle(const sid: integer): TSVGStyleItem;
     364     procedure SetStyle(const sid: integer; sr: TSVGStyleItem);
     365     function Find(sr: TSVGStyleItem): integer; overload;
     366   protected
     367     procedure Initialize; override;
     368   public
     369     constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; override;
     370     constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
     371       AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; override;
     372     destructor Destroy; override;
     373     function Count: Integer;
     374     function Find(const AName: string): integer; overload;
     375     function Add(sr: TSVGStyleItem): integer;
     376     procedure Remove(sr: TSVGStyleItem);
     377     procedure Clear;
     378     procedure ReParse;
     379     property Styles[sid: integer]: TSVGStyleItem read GetStyle write SetStyle;
     380  end;                 
    199381
    200382  { TSVGContent }
     
    202384  TSVGContent = class
    203385    protected
     386      FDataLink: TSVGDataLink;
    204387      FDomElem: TDOMElement;
    205388      FDoc: TXMLDocument;
    206       FElements: TList;
     389      FElements: TFPList;
    207390      FUnits: TCSSUnitConverter;
    208391      procedure AppendElement(AElement: TSVGElement);
     
    212395      function GetUnits: TCSSUnitConverter;
    213396    public
    214       constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter);
     397      constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter;
     398        ADataLink: TSVGDataLink; ADataParent: TSVGElement);
    215399      destructor Destroy; override;
     400      procedure Recompute;
    216401      procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; AUnit: TCSSUnit); overload;
    217402      procedure Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); overload;
     
    239424function GetSVGFactory(ATagName: string): TSVGFactory;
    240425function CreateSVGElementFromNode(ADocument: TXMLDocument;
    241   AElement: TDOMElement; AUnits: TCSSUnitConverter): TSVGElement;
     426  AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
    242427
    243428implementation
     
    263448  if tag='text' then
    264449    result := TSVGText else
     450  if tag='lineargradient' then
     451    result := TSVGLinearGradient else
     452  if tag='radialgradient' then
     453    result := TSVGRadialGradient else
     454  if tag='stop' then
     455    result := TSVGStopGradient else
     456  if tag='defs' then
     457    result := TSVGDefine else
    265458  if tag='g' then
    266459    result := TSVGGroup else
     460  if tag='style' then
     461    result := TSVGStyle else
    267462    result := TSVGElement;
    268463end;
    269464
    270465function CreateSVGElementFromNode(ADocument: TXMLDocument;
    271   AElement: TDOMElement; AUnits: TCSSUnitConverter): TSVGElement;
     466  AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
    272467var
    273468  factory: TSVGFactory;
    274469begin
    275470  factory := GetSVGFactory(AElement.TagName);
    276   result := factory.Create(ADocument,AElement,AUnits);
    277 end;
     471  result := factory.Create(ADocument,AElement,AUnits,ADataLink);
     472 
     473  ADataLink.Link(result,ADataParent);
     474end;
     475
     476{ TSVGElementWithGradient }
     477
     478procedure TSVGElementWithGradient.Initialize;
     479begin
     480  inherited Initialize;
     481  ResetGradient;
     482end;
     483
     484procedure TSVGElementWithGradient.ResetGradient;
     485begin
     486  FGradientElementDefined := false;
     487  FGradientElement        := nil;
     488  FCanvasGradient         := nil;
     489end;
     490
     491function TSVGElementWithGradient.FindGradientElement: boolean;
     492var
     493  i: integer;
     494  s: string;
     495begin
     496  Result:= false;
     497  s:= fill;
     498  if s <> '' then
     499    if Pos('url(#',s) = 1 then
     500    begin
     501      s:= System.Copy(s,6,Length(s)-6);
     502      with FDataLink do
     503        for i:= GradientCount-1 downto 0 do
     504          if (Gradients[i] as TSVGGradient).ID = s then
     505          begin
     506            FGradientElement:= TSVGGradient(Gradients[i]);
     507            Result:= true;
     508            Exit;
     509          end;
     510    end;
     511end;
     512
     513function TSVGElementWithGradient.EvaluatePercentage(fu: TFloatWithCSSUnit): single;
     514begin
     515  Result:= fu.value;
     516  if fu.CSSUnit <> cuPercent then
     517  begin
     518    if Result < 0 then
     519      Result:= 0
     520    else if Result > 1 then
     521      Result:= 1;
     522    Result:= Result * 100;
     523  end;
     524end;
     525
     526function TSVGElementWithGradient.GetGradientElement: TSVGGradient;
     527begin
     528  if not FGradientElementDefined then
     529  begin
     530    FindGradientElement;
     531    FGradientElementDefined:= true;
     532    if FGradientElement <> nil then
     533      FGradientElement.ScanInheritedGradients;
     534  end;
     535  result := FGradientElement;
     536end;
     537
     538procedure TSVGElementWithGradient.AddStopElements(canvas: IBGRACanvasGradient2D);
     539
     540  function AddStopElementFrom(el: TSVGElement): integer;
     541  var
     542    i: integer;
     543    col: TBGRAPixel;
     544  begin
     545    result:= 0;
     546    with el.DataChildList do
     547      for i:= 0 to Count-1 do
     548        if Items[i] is TSVGStopGradient then
     549          with (Items[i] as TSVGStopGradient) do
     550          begin
     551            col:= StrToBGRA( AttributeOrStyleDef['stop-color','black'] );
     552            col.alpha:= Round( Units.parseValue(AttributeOrStyleDef['stop-opacity','1'],1) * col.alpha );
     553            canvas.addColorStop(EvaluatePercentage(offset)/100, col);
     554            Inc(result);
     555          end;
     556  end;
     557
     558var
     559  i: integer;
     560begin
     561  if not Assigned(GradientElement) then exit;
     562  with GradientElement.InheritedGradients do
     563    for i:= 0 to Count-1 do
     564      AddStopElementFrom(Items[i]);
     565end;
     566
     567procedure TSVGElementWithGradient.CreateCanvasLinearGradient(
     568  ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
     569  const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
     570var p1,p2: TPointF;
     571  g: TSVGLinearGradient;
     572  m: TAffineMatrix;
     573begin
     574  g := ASVGGradient as TSVGLinearGradient;
     575  if g.useObjectBoundingBox then
     576  begin
     577    p1.x:= EvaluatePercentage(g.x1)/100;
     578    p1.y:= EvaluatePercentage(g.y1)/100;
     579    p2.x:= EvaluatePercentage(g.x2)/100;
     580    p2.y:= EvaluatePercentage(g.y2)/100;
     581    m := ACanvas2d.matrix;
     582    ACanvas2d.translate(origin.x,origin.y);
     583    ACanvas2d.scale(w,h);
     584    ACanvas2d.transform(g.gradientMatrix[cuCustom]);
     585    FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
     586    ACanvas2d.matrix := m;
     587  end else
     588  begin
     589    p1.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
     590    p1.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
     591    p2.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
     592    p2.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
     593    m := ACanvas2d.matrix;
     594    ACanvas2d.transform(g.gradientMatrix[AUnit]);
     595    FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
     596    ACanvas2d.matrix := m;
     597  end;
     598
     599  AddStopElements(FCanvasGradient);
     600end;
     601
     602procedure TSVGElementWithGradient.CreateCanvasRadialGradient(
     603  ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient; const origin: TPointF;
     604  const w, h: single; AUnit: TCSSUnit);
     605var c,f: TPointF;
     606  r,fr: single;
     607  g: TSVGRadialGradient;
     608  m: TAffineMatrix;
     609
     610  procedure CheckFocalAndCreate(c: TPointF; r: single; f: TPointF; fr: single);
     611  var u: TPointF;
     612    d: single;
     613  begin
     614    u := f-c;
     615    d := VectLen(u);
     616    if d >= r then
     617    begin
     618      u *= (r/d)*0.99999;
     619      f := c+u;
     620    end;
     621    FCanvasGradient:= ACanvas2d.createRadialGradient(c,r,f,fr,true);
     622    AddStopElements(FCanvasGradient);
     623  end;
     624
     625begin
     626  g := ASVGGradient as TSVGRadialGradient;
     627  if g.useObjectBoundingBox then
     628  begin
     629    c.x:= EvaluatePercentage(g.cx)/100;
     630    c.y:= EvaluatePercentage(g.cy)/100;
     631    r:= abs(EvaluatePercentage(g.r))/100;
     632    f.x:= EvaluatePercentage(g.fx)/100;
     633    f.y:= EvaluatePercentage(g.fy)/100;
     634    fr:= abs(EvaluatePercentage(g.fr))/100;
     635
     636    m := ACanvas2d.matrix;
     637    ACanvas2d.translate(origin.x,origin.y);
     638    ACanvas2d.scale(w,h);
     639    ACanvas2d.transform(g.gradientMatrix[cuCustom]);
     640    CheckFocalAndCreate(c,r,f,fr);
     641    ACanvas2d.matrix := m;
     642  end else
     643  begin
     644    c.x:= Units.ConvertWidth(g.cx,AUnit,w).value;
     645    c.y:= Units.ConvertHeight(g.cy,AUnit,h).value;
     646    r:= abs(Units.ConvertWidth(g.r,AUnit,w).value);
     647    f.x:= Units.ConvertWidth(g.fx,AUnit,w).value;
     648    f.y:= Units.ConvertHeight(g.fy,AUnit,h).value;
     649    fr:= abs(Units.ConvertWidth(g.fr,AUnit,w).value);
     650
     651    m := ACanvas2d.matrix;
     652    ACanvas2d.transform(g.gradientMatrix[AUnit]);
     653    CheckFocalAndCreate(c,r,f,fr);
     654    ACanvas2d.matrix := m;
     655  end;
     656end;
     657
     658procedure TSVGElementWithGradient.InitializeGradient(ACanvas2d: TBGRACanvas2D;
     659  const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
     660begin
     661  if GradientElement <> nil then
     662  begin
     663    if GradientElement is TSVGLinearGradient then
     664      CreateCanvasLinearGradient(ACanvas2d, GradientElement, origin, w,h, AUnit)
     665    else
     666    if GradientElement is TSVGRadialGradient then
     667      CreateCanvasRadialGradient(ACanvas2d, GradientElement, origin, w,h, AUnit);
     668  end;
     669end;
     670
     671procedure TSVGElementWithGradient.ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit);
     672begin
     673  if FCanvasGradient = nil then
     674    inherited ApplyFillStyle(ACanvas2D,AUnit)
     675  else
     676  begin
     677    ACanvas2D.fillStyle(FCanvasGradient);
     678    ACanvas2D.fillMode:= TFillMode(fillMode);
     679  end;
     680end; 
    278681
    279682{ TSVGText }
     
    290693function TSVGText.GetFontFamily: string;
    291694begin
    292   result := AttributeOrStyle['font-family'];
    293   if result = '' then result := 'Arial';
     695  result := AttributeOrStyleDef['font-family','Arial'];
    294696end;
    295697
     
    303705function TSVGText.GetFontSize: TFloatWithCSSUnit;
    304706begin
    305   if AttributeOrStyle['font-size']='' then
    306     result := FloatWithCSSUnit(12,cuPoint)
    307   else
    308     result := VerticalAttributeOrStyleWithUnit['font-size'];
     707  result:= VerticalAttributeOrStyleWithUnit['font-size',FloatWithCSSUnit(12,cuPoint)];
    309708end;
    310709
    311710function TSVGText.GetFontStyle: string;
    312711begin
    313   result := AttributeOrStyle['font-style'];
    314   if result = '' then result := 'normal';
     712  result := AttributeOrStyleDef['font-style','normal'];
    315713end;
    316714
    317715function TSVGText.GetFontWeight: string;
    318716begin
    319   result := AttributeOrStyle['font-weight'];
    320   if result = '' then result := 'normal';
     717  result := AttributeOrStyleDef['font-weight','normal'];
    321718end;
    322719
     
    328725function TSVGText.GetTextDecoration: string;
    329726begin
    330   result := AttributeOrStyle['text-decoration'];
    331   if result='' then result := 'none';
     727  result := AttributeOrStyleDef['text-decoration','none'];
    332728end;
    333729
     
    397793
    398794procedure TSVGText.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
    399 var fs:TFontStyles;
     795var
     796  fs:TFontStyles;
     797  vx,vy: single;
    400798begin
    401799  ACanvas2d.beginPath;
    402   ACanvas2d.fontEmHeight := Units.ConvertWidth(fontSize,AUnit).value;
     800  ACanvas2d.fontEmHeight := Units.ConvertHeight(fontSize,AUnit).value;
    403801  ACanvas2d.fontName := fontFamily;
    404802  fs := [];
     
    406804  if fontItalic then fs += [fsItalic];
    407805  ACanvas2d.fontStyle := fs;
    408   ACanvas2d.text(SimpleText,Units.ConvertWidth(x,AUnit).value,Units.ConvertWidth(y,AUnit).value);
     806  vx:= Units.ConvertWidth(x,AUnit).value;
     807  vy:= Units.ConvertHeight(y,AUnit).value;
     808  ACanvas2d.text(SimpleText,vx,vy);
     809
     810  if Assigned(GradientElement) then
     811    with ACanvas2d.measureText(SimpleText) do
     812      InitializeGradient(ACanvas2d, PointF(vx,vy),width,height,AUnit);
     813             
    409814  if not isFillNone then
    410815  begin
    411     ACanvas2d.fillStyle(fillColor);
     816    ApplyFillStyle(ACanvas2D,AUnit);
    412817    ACanvas2d.fill;
    413818  end;
     
    419824end;
    420825
    421 constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter);
    422 begin
     826constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     827begin
     828  inherited Create(ADocument, AUnits, ADataLink);
    423829  Init(ADocument,'text',AUnits);
    424830end;
     
    426832{ TSVGGroup }
    427833
    428 constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter);
    429 begin
    430   inherited Create(ADocument, AUnits);
    431   FContent := TSVGContent.Create(ADocument,FDomElem,AUnits);
     834constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     835begin
     836  inherited Create(ADocument, AUnits, ADataLink);
     837  FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
    432838end;
    433839
    434840constructor TSVGGroup.Create(ADocument: TXMLDocument; AElement: TDOMElement;
    435   AUnits: TCSSUnitConverter);
    436 begin
    437   inherited Create(ADocument, AElement, AUnits);
    438   FContent := TSVGContent.Create(ADocument,AElement,AUnits);
     841  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     842begin
     843  inherited Create(ADocument, AElement, AUnits, ADataLink);
     844  FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
    439845end;
    440846
     
    450856end;
    451857
     858procedure TSVGGroup.Recompute;
     859begin
     860  inherited Recompute;
     861  FContent.Recompute;
     862end;
     863
     864{ TSVGStyle } 
     865
     866constructor TSVGStyle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     867begin
     868  inherited Create(ADocument, AUnits, ADataLink);
     869  Init(ADocument,'style',AUnits);
     870end;
     871
     872constructor TSVGStyle.Create(ADocument: TXMLDocument; AElement: TDOMElement;
     873  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     874begin
     875  inherited Create(ADocument, AElement, AUnits, ADataLink);
     876  Parse(AElement.TextContent);
     877end;
     878
     879procedure TSVGStyle.Initialize;
     880begin
     881  inherited Initialize;
     882  Clear;
     883end;
     884
     885destructor TSVGStyle.Destroy;
     886begin
     887  Clear;
     888  inherited Destroy;
     889end;
     890
     891procedure TSVGStyle.Parse(const s: String);
     892
     893  function IsValidAttribute(const sa: string): boolean;
     894  var
     895    i: integer;
     896  begin
     897    //(for case example "{ ; ;}")
     898    for i:= 1 to Length(sa) do
     899     if not (sa[i] in [' ',';']) then
     900      exit(true);
     901    result:= false;
     902  end;
     903
     904const
     905  EmptyRec: TSVGStyleItem = (name: ''; attribute: '');
     906var
     907  i,l,pg: integer;
     908  st: String;
     909  rec: TSVGStyleItem;
     910begin
     911  (*
     912    Example of internal style block
     913    circle {..}         
     914    circle.type1 {..}   
     915    .pic1 {..}         
     916  *)
     917  Clear;
     918  l:= 0;
     919  pg:= 0;
     920  st:= '';
     921  rec:= EmptyRec;
     922  for i:= 1 to Length(s) do
     923  begin
     924    if s[i] = '{' then
     925    begin
     926      Inc(pg);
     927      if (pg = 1) and (Length(st) <> 0) then
     928      begin
     929       rec.name:= Trim(st);
     930       st:= '';
     931      end;
     932    end
     933    else if s[i] = '}' then
     934    begin
     935      Dec(pg);
     936      if (pg = 0) and (Length(st) <> 0) then
     937      begin
     938        if IsValidAttribute(st) then
     939        begin
     940          rec.attribute:= Trim(st);
     941          Inc(l);
     942          SetLength(FStyles,l);
     943          FStyles[l-1]:= rec;
     944          rec:= EmptyRec;
     945        end;
     946        st:= '';
     947      end;
     948    end
     949    else
     950      st:= st + s[i];
     951  end;
     952end;
     953
     954function TSVGStyle.IsValidID(const sid: integer): boolean;
     955begin
     956  result:= (sid >= 0) and (sid < Length(FStyles));
     957end;
     958
     959function TSVGStyle.GetStyle(const sid: integer): TSVGStyleItem;
     960begin
     961  if IsValidID(sid) then
     962    result:= FStyles[sid]
     963  else
     964    raise exception.Create(rsInvalidId);
     965end;
     966
     967procedure TSVGStyle.SetStyle(const sid: integer; sr: TSVGStyleItem);
     968begin
     969  if IsValidID(sid) then
     970    FStyles[sid]:= sr
     971  else
     972    raise exception.Create(rsInvalidId);
     973end;
     974
     975function TSVGStyle.Count: Integer;
     976begin
     977  result:= Length(FStyles);
     978end;
     979
     980function TSVGStyle.Find(sr: TSVGStyleItem): integer;
     981var
     982  i: integer;
     983begin
     984  for i:= 0 to Length(FStyles)-1 do
     985    with FStyles[i] do
     986      if (name = sr.name) and
     987         (attribute = sr.attribute) then
     988      begin
     989        result:= i;
     990        Exit;
     991      end;
     992  result:= -1;
     993end;
     994
     995function TSVGStyle.Find(const AName: string): integer;
     996var
     997  i: integer;
     998begin
     999  for i:= 0 to Length(FStyles)-1 do
     1000    with FStyles[i] do
     1001      if name = AName then
     1002      begin
     1003        result:= i;
     1004        Exit;
     1005      end;
     1006  result:= -1;
     1007end;
     1008
     1009function TSVGStyle.Add(sr: TSVGStyleItem): integer;
     1010var
     1011  l: integer;
     1012begin
     1013  l:= Length(FStyles);
     1014  SetLength(FStyles,l+1);
     1015  FStyles[l]:= sr;
     1016  result:= l;
     1017end;
     1018
     1019procedure TSVGStyle.Remove(sr: TSVGStyleItem);
     1020var
     1021  l,p: integer;
     1022begin
     1023  p:= Find(sr);
     1024  l:= Length(FStyles);
     1025  if p <> -1 then
     1026  begin
     1027    Finalize(FStyles[p]);
     1028    System.Move(FStyles[p+1], FStyles[p], (l-p)*SizeOf(TSVGStyleItem));
     1029    SetLength(FStyles,l-1);
     1030  end;
     1031end;
     1032
     1033procedure TSVGStyle.Clear;
     1034begin
     1035  SetLength(FStyles,0);
     1036end;
     1037
     1038procedure TSVGStyle.ReParse;
     1039begin
     1040 Parse(FDomElem.TextContent);
     1041end;           
     1042
    4521043{ TSVGRectangle }
    4531044
     
    5131104
    5141105constructor TSVGRectangle.Create(ADocument: TXMLDocument;
    515   AUnits: TCSSUnitConverter);
    516 begin
     1106  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1107begin
     1108  inherited Create(ADocument, AUnits, ADataLink);
    5171109  Init(ADocument,'rect',AUnits);
    5181110end;
    5191111
    5201112procedure TSVGRectangle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
     1113var
     1114  vx,vy,vw,vh: Single;
    5211115begin
    5221116  if not isStrokeNone or not isFillNone then
    5231117  begin
     1118    vx:= Units.ConvertWidth(x,AUnit).value;
     1119    vy:= Units.ConvertHeight(y,AUnit).value;
     1120    vw:= Units.ConvertWidth(width,AUnit).value;
     1121    vh:= Units.ConvertHeight(height,AUnit).value;
    5241122    ACanvas2d.beginPath;
    525     ACanvas2d.roundRect(Units.ConvertWidth(x,AUnit).value,Units.ConvertWidth(y,AUnit).value,
    526        Units.ConvertWidth(width,AUnit).value,Units.ConvertWidth(height,AUnit).value,
    527        Units.ConvertWidth(rx,AUnit).value,Units.ConvertWidth(ry,AUnit).value);
     1123    ACanvas2d.roundRect(vx,vy, vw,vh,
     1124       Units.ConvertWidth(rx,AUnit).value,Units.ConvertHeight(ry,AUnit).value);
     1125    if Assigned(GradientElement) then
     1126      InitializeGradient(ACanvas2d, PointF(vx,vy),vw,vh,AUnit);
    5281127    if not isFillNone then
    5291128    begin
    530       ACanvas2d.fillStyle(fillColor);
     1129      ApplyFillStyle(ACanvas2D,AUnit);
    5311130      ACanvas2d.fill;
    5321131    end;
     
    5441143begin
    5451144  result := FDomElem.TagName = 'polygon';
     1145end;
     1146
     1147function TSVGPolypoints.GetBoundingBoxF: TRectF;
     1148begin
     1149  if not FBoundingBoxComputed then
     1150    ComputeBoundingBox(pointsF);
     1151  result := FBoundingBox;
    5461152end;
    5471153
     
    5701176    result[i].y := parser.ParseFloat;
    5711177  end;
     1178  parser.Free;
    5721179end;
    5731180
     
    5891196  end;
    5901197  points := s;
     1198  ComputeBoundingBox(AValue);
     1199end;
     1200
     1201procedure TSVGPolypoints.ComputeBoundingBox(APoints: ArrayOfTPointF);
     1202var
     1203  i: Integer;
     1204begin
     1205  if length(APoints) > 1 then
     1206  begin
     1207    with APoints[0] do
     1208      FBoundingBox:= RectF(x,y,x,y);
     1209    for i:= 1 to high(APoints) do
     1210      with APoints[i] do
     1211      begin
     1212        if x < FBoundingBox.Left then
     1213         FBoundingBox.Left:= x
     1214        else if x > FBoundingBox.Right then
     1215         FBoundingBox.Right:= x;
     1216        if y < FBoundingBox.Top then
     1217         FBoundingBox.Top:= y
     1218        else if y > FBoundingBox.Bottom then
     1219         FBoundingBox.Bottom:= y;
     1220      end;
     1221    FBoundingBoxComputed := true;
     1222  end else
     1223  begin
     1224    FBoundingBox := RectF(0,0,0,0);
     1225    FBoundingBoxComputed := true;
     1226  end;
    5911227end;
    5921228
    5931229constructor TSVGPolypoints.Create(ADocument: TXMLDocument;
    594   AUnits: TCSSUnitConverter; AClosed: boolean);
    595 begin
     1230  AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink);
     1231begin
     1232  inherited Create(ADocument, AUnits, ADataLink);
    5961233  if AClosed then
    5971234    Init(ADocument, 'polygon', AUnits)
     
    6081245var
    6091246  prevMatrix: TAffineMatrix;
     1247  pts: ArrayOfTPointF;
    6101248begin
    6111249  if isFillNone and isStrokeNone then exit;
     
    6201258  begin
    6211259    ACanvas2d.beginPath;
    622     ACanvas2d.polylineTo(pointsF);
     1260    pts := pointsF;
     1261    ACanvas2d.polylineTo(pts);
    6231262    if closed then ACanvas2d.closePath;
     1263   
     1264    with boundingBoxF do
     1265      InitializeGradient(ACanvas2d,
     1266        PointF(Left,Top),abs(Right-Left),abs(Bottom-Top),AUnit);
     1267   
    6241268    if not isFillNone then
    6251269    begin
    626       ACanvas2d.fillStyle(fillColor);
     1270      ApplyFillStyle(ACanvas2D,AUnit);
    6271271      ACanvas2d.fill;
    6281272    end;
     
    6491293end;
    6501294
     1295function TSVGPath.GetBoundingBoxF: TRectF;
     1296begin
     1297  if not FBoundingBoxComputed then
     1298  begin
     1299    FBoundingBox := path.GetBounds;
     1300    FBoundingBoxComputed := true;
     1301  end;
     1302  result := FBoundingBox;
     1303end;
     1304
    6511305function TSVGPath.GetData: string;
    6521306begin
     
    6681322  else
    6691323    FPath.SvgString := AValue;
     1324  FBoundingBoxComputed := false;
    6701325end;
    6711326
     
    6761331end;
    6771332
    678 constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter);
    679 begin
     1333constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1334begin
     1335  inherited Create(ADocument, AUnits, ADataLink);
    6801336  Init(ADocument,'path',AUnits);
    6811337  FPath := nil;
     1338  FBoundingBoxComputed := false;
     1339  FBoundingBox := rectF(0,0,0,0);
    6821340end;
    6831341
    6841342constructor TSVGPath.Create(ADocument: TXMLDocument; AElement: TDOMElement;
    685   AUnits: TCSSUnitConverter);
    686 begin
     1343  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1344begin
     1345  inherited Create(ADocument, AElement, AUnits, ADataLink);
    6871346  Init(ADocument, AElement, AUnits);
    6881347  FPath := nil;
     1348  FBoundingBoxComputed := false;
     1349  FBoundingBox := rectF(0,0,0,0);
    6891350end;
    6901351
     
    7101371  begin
    7111372    ACanvas2d.path(path);
     1373    if Assigned(GradientElement) then
     1374      with boundingBoxF do
     1375        InitializeGradient(ACanvas2d,
     1376          PointF(Left,Top),abs(Right-Left),abs(Bottom-Top),AUnit);
    7121377    if not isFillNone then
    7131378    begin
    714       ACanvas2d.fillStyle(fillColor);
     1379      ApplyFillStyle(ACanvas2D,AUnit);
    7151380      ACanvas2d.fill;
    7161381    end;
     
    7661431
    7671432constructor TSVGEllipse.Create(ADocument: TXMLDocument;
    768   AUnits: TCSSUnitConverter);
    769 begin
     1433  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1434begin
     1435  inherited Create(ADocument, AUnits, ADataLink);
    7701436  Init(ADocument,'ellipse',AUnits);
    7711437end;
    7721438
    7731439procedure TSVGEllipse.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
     1440var
     1441  vcx,vcy,vrx,vry: Single;
    7741442begin
    7751443  if not isFillNone or not isStrokeNone then
    7761444  begin
     1445    vcx:= Units.ConvertWidth(cx,AUnit).value;
     1446    vcy:= Units.ConvertHeight(cy,AUnit).value;
     1447    vrx:= Units.ConvertWidth(rx,AUnit).value;
     1448    vry:= Units.ConvertHeight(ry,AUnit).value;
    7771449    ACanvas2d.beginPath;
    778     ACanvas2d.ellipse(Units.ConvertWidth(cx,AUnit).value,Units.ConvertWidth(cy,AUnit).value,
    779          Units.ConvertWidth(rx,AUnit).value,Units.ConvertWidth(ry,AUnit).value);
     1450    ACanvas2d.ellipse(vcx,vcy,vrx,vry);
     1451    if Assigned(GradientElement) then
     1452      InitializeGradient(ACanvas2d, PointF(vcx-vrx,vcy-vry),vrx*2,vry*2,AUnit);     
    7801453    if not isFillNone then
    7811454    begin
    782       ACanvas2d.fillStyle(fillColor);
     1455      ApplyFillStyle(ACanvas2D,AUnit);
    7831456      ACanvas2d.fill;
    7841457    end;
     
    8231496end;
    8241497
    825 constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter);
    826 begin
     1498constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1499begin
     1500  inherited Create(ADocument, AUnits, ADataLink);
    8271501  Init(ADocument,'circle',AUnits);
    8281502end;
    8291503
    8301504procedure TSVGCircle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
     1505var
     1506  vcx,vcy,vr: Single;
    8311507begin
    8321508  if not isFillNone or not isStrokeNone then
    8331509  begin
     1510    vcx:= Units.ConvertWidth(cx,AUnit).value;
     1511    vcy:= Units.ConvertHeight(cy,AUnit).value;
     1512    vr:= Units.ConvertWidth(r,AUnit).value;
    8341513    ACanvas2d.beginPath;
    835     ACanvas2d.circle(Units.ConvertWidth(cx,AUnit).value,Units.ConvertWidth(cy,AUnit).value,
    836          Units.ConvertWidth(r,AUnit).value);
     1514    ACanvas2d.circle(vcx,vcy,vr);
     1515    if Assigned(GradientElement) then
     1516      InitializeGradient(ACanvas2d, PointF(vcx-vr,vcy-vr),vr*2,vr*2,AUnit);
    8371517    if not isFillNone then
    8381518    begin
    839       ACanvas2d.fillStyle(fillColor);
     1519      ApplyFillStyle(ACanvas2D,AUnit);
    8401520      ACanvas2d.fill;
    8411521    end;
     
    8901570end;
    8911571
    892 constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter);
    893 begin
     1572constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1573begin
     1574  inherited Create(ADocument, AUnits, ADataLink);
    8941575  Init(ADocument,'line',AUnits);
    8951576end;
     
    9011582    ApplyStrokeStyle(ACanvas2D,AUnit);
    9021583    ACanvas2d.beginPath;
    903     ACanvas2d.moveTo(Units.ConvertWidth(x1,AUnit).value,Units.ConvertWidth(y1,AUnit).value);
    904     ACanvas2d.lineTo(Units.ConvertWidth(x2,AUnit).value,Units.ConvertWidth(y2,AUnit).value);
     1584    ACanvas2d.moveTo(Units.ConvertWidth(x1,AUnit).value,Units.ConvertHeight(y1,AUnit).value);
     1585    ACanvas2d.lineTo(Units.ConvertWidth(x2,AUnit).value,Units.ConvertHeight(y2,AUnit).value);
    9051586    ACanvas2d.stroke;
    9061587  end;
     1588end;
     1589
     1590{ TSVGGradient } //##
     1591
     1592function TSVGGradient.GetHRef: string;
     1593begin
     1594  result := Attribute['xlink:href'];
     1595  if result = '' then
     1596    result := Attribute['href'];//(Note: specific for svg 2)
     1597end;
     1598
     1599function TSVGGradient.GetUseObjectBoundingBox: boolean;
     1600begin
     1601  result := (gradientUnits = 'objectBoundingBox');
     1602end;
     1603
     1604procedure TSVGGradient.SetGradientTransform(AValue: string);
     1605begin
     1606  Attribute['gradientTransform'] := AValue;
     1607end;
     1608
     1609function TSVGGradient.GetGradientUnits: string;
     1610begin
     1611  result := AttributeDef['gradientUnits','objectBoundingBox'];
     1612end;
     1613
     1614function TSVGGradient.GetGradientTransform: string;
     1615begin
     1616  result := Attribute['gradientTransform'];
     1617end;
     1618
     1619function TSVGGradient.GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
     1620var parser: TSVGParser;
     1621  s: string;
     1622begin
     1623  s := gradientTransform;
     1624  if s = '' then
     1625  begin
     1626    result := AffineMatrixIdentity;
     1627    exit;
     1628  end;
     1629  parser := TSVGParser.Create(s);
     1630  result := parser.ParseTransform;
     1631  parser.Free;
     1632  result[1,3] := Units.ConvertWidth(result[1,3],cuCustom,AUnit);
     1633  result[2,3] := Units.ConvertHeight(result[2,3],cuCustom,AUnit);
     1634end;
     1635
     1636procedure TSVGGradient.SetGradientUnits(AValue: string);
     1637begin
     1638  Attribute['gradientUnits'] := AValue;
     1639end;
     1640
     1641procedure TSVGGradient.SetHRef(AValue: string);
     1642begin
     1643  Attribute['xlink:href'] := AValue;
     1644end;
     1645
     1646constructor TSVGGradient.Create(ADocument: TXMLDocument;
     1647  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1648begin
     1649  inherited Create(ADocument, AUnits, ADataLink);
     1650  FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
     1651end;
     1652
     1653function TSVGGradient.HRefToGradientID(const AValue: string): string;
     1654var
     1655  l: integer;
     1656begin
     1657  //(example input: "#gradient1")
     1658  l:= Length(AValue);
     1659  if l < 2 then
     1660    result:= ''
     1661  else
     1662    result:= System.Copy(AValue,2,l-1);
     1663end;
     1664
     1665function TSVGGradient.FindGradientRef(const AGradientID: string): integer;
     1666var
     1667  i: integer;
     1668begin
     1669  with FDataLink do
     1670    for i:= 0 to GradientCount-1 do
     1671      if (Gradients[i] as TSVGGradient).ID = AGradientID then
     1672      begin
     1673        result:= i;
     1674        exit;
     1675      end;
     1676  result:= -1;
     1677end;
     1678
     1679procedure TSVGGradient.Initialize;
     1680begin
     1681  inherited;
     1682  InheritedGradients:= TSVGElementList.Create;
     1683end;
     1684
     1685function TSVGGradient.GetInheritedAttribute(AValue: string;
     1686  AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
     1687var
     1688  i: integer;
     1689  el: TSVGGradient;
     1690  invalidDef: TFloatWithCSSUnit;
     1691begin
     1692  invalidDef:= FloatWithCSSUnit(EmptySingle,cuPercent);
     1693  //find valid inherited attribute (start from "self": item[0])
     1694  for i:= 0 to InheritedGradients.Count-1 do
     1695  begin
     1696    el:= TSVGGradient( InheritedGradients[i] );
     1697    with el do
     1698    begin
     1699      if AConvMethod = cmHoriz then
     1700        result:= HorizAttributeWithUnitDef[AValue,invalidDef]
     1701      else if AConvMethod = cmVertical then
     1702        result:= VerticalAttributeWithUnitDef[AValue,invalidDef]
     1703      else if AConvMethod = cmOrtho then
     1704        result:= OrthoAttributeWithUnitDef[AValue,invalidDef]
     1705      else
     1706        result:= AttributeWithUnitDef[AValue,invalidDef];
     1707
     1708      if (result.value <> invalidDef.value) or
     1709         (result.CSSUnit <> invalidDef.CSSUnit) then
     1710        exit;
     1711    end;
     1712  end;
     1713  result:= ADefault;
     1714end;
     1715
     1716constructor TSVGGradient.Create(ADocument: TXMLDocument; AElement: TDOMElement;
     1717  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1718begin
     1719  inherited Create(ADocument, AElement, AUnits, ADataLink);
     1720  FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
     1721end;
     1722
     1723destructor TSVGGradient.Destroy;
     1724begin
     1725  FreeAndNil(FContent);
     1726  FreeAndNil(InheritedGradients);
     1727  inherited Destroy;
     1728end;
     1729
     1730procedure TSVGGradient.Recompute;
     1731begin
     1732  inherited Recompute;
     1733  FContent.Recompute;
     1734end;
     1735
     1736procedure TSVGGradient.ScanInheritedGradients(const forceScan: boolean = false);
     1737var
     1738  el: TSVGGradient;
     1739  pos: integer;
     1740  gradientID: string;
     1741begin
     1742  //(if list empty = not scan)
     1743  if (InheritedGradients.Count <> 0) and (not forceScan) then
     1744    exit;
     1745
     1746  InheritedGradients.Clear;
     1747  InheritedGradients.Add(Self);//(important)
     1748  el:= Self;
     1749  while el.hRef <> '' do
     1750  begin
     1751    gradientID:= HRefToGradientID(el.hRef);
     1752    pos:= FindGradientRef(gradientID);
     1753    if pos = -1 then
     1754      exit
     1755    else
     1756    begin
     1757      el:= TSVGGradient(FDataLink.Gradients[pos]);
     1758      InheritedGradients.Add(el);
     1759    end;
     1760  end;
     1761end;       
     1762
     1763{ TSVGLinearGradient }
     1764
     1765function TSVGLinearGradient.GetX1: TFloatWithCSSUnit;
     1766begin
     1767  result := GetInheritedAttribute('x1',cmNone,FloatWithCSSUnit(0,cuPercent));
     1768end;
     1769
     1770function TSVGLinearGradient.GetX2: TFloatWithCSSUnit;
     1771begin
     1772  result := GetInheritedAttribute('x2',cmNone,FloatWithCSSUnit(100,cuPercent));
     1773end;
     1774
     1775function TSVGLinearGradient.GetY1: TFloatWithCSSUnit;
     1776begin
     1777  result := GetInheritedAttribute('y1',cmNone,FloatWithCSSUnit(0,cuPercent));
     1778end;
     1779
     1780function TSVGLinearGradient.GetY2: TFloatWithCSSUnit;
     1781begin
     1782  result := GetInheritedAttribute('y2',cmNone,FloatWithCSSUnit(0,cuPercent));
     1783end;
     1784
     1785procedure TSVGLinearGradient.SetX1(AValue: TFloatWithCSSUnit);
     1786begin
     1787  AttributeWithUnit['x1']:= AValue;
     1788end;
     1789
     1790procedure TSVGLinearGradient.SetX2(AValue: TFloatWithCSSUnit);
     1791begin
     1792  AttributeWithUnit['x2']:= AValue;
     1793end;
     1794
     1795procedure TSVGLinearGradient.SetY1(AValue: TFloatWithCSSUnit);
     1796begin
     1797  AttributeWithUnit['y1']:= AValue;
     1798end;
     1799
     1800procedure TSVGLinearGradient.SetY2(AValue: TFloatWithCSSUnit);
     1801begin
     1802  AttributeWithUnit['y2']:= AValue;
     1803end;
     1804
     1805constructor TSVGLinearGradient.Create(ADocument: TXMLDocument;
     1806  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1807begin
     1808  inherited Create(ADocument, AUnits, ADataLink);
     1809  Init(ADocument,'linearGradient',AUnits);
     1810end;
     1811
     1812{ TSVGRadialGradient }
     1813
     1814function TSVGRadialGradient.GetCX: TFloatWithCSSUnit;
     1815begin
     1816  result := GetInheritedAttribute('cx',cmHoriz,FloatWithCSSUnit(50,cuPercent));
     1817end;
     1818
     1819function TSVGRadialGradient.GetCY: TFloatWithCSSUnit;
     1820begin
     1821  result := GetInheritedAttribute('cy',cmVertical,FloatWithCSSUnit(50,cuPercent));
     1822end;
     1823
     1824function TSVGRadialGradient.GetR: TFloatWithCSSUnit;
     1825begin
     1826  result := GetInheritedAttribute('r',cmOrtho,FloatWithCSSUnit(50,cuPercent));
     1827end;
     1828
     1829function TSVGRadialGradient.GetFX: TFloatWithCSSUnit;
     1830begin
     1831  result := GetInheritedAttribute('fx',cmHoriz,cx);
     1832end;
     1833
     1834function TSVGRadialGradient.GetFY: TFloatWithCSSUnit;
     1835begin
     1836  result := GetInheritedAttribute('fy',cmVertical,cy);
     1837end;         
     1838
     1839function TSVGRadialGradient.GetFR: TFloatWithCSSUnit;
     1840begin
     1841  result := GetInheritedAttribute('fr',cmHoriz,FloatWithCSSUnit(0,cuPercent));
     1842end;
     1843
     1844procedure TSVGRadialGradient.SetCX(AValue: TFloatWithCSSUnit);
     1845begin
     1846  HorizAttributeWithUnit['cx'] := AValue;
     1847end;
     1848
     1849procedure TSVGRadialGradient.SetCY(AValue: TFloatWithCSSUnit);
     1850begin
     1851  VerticalAttributeWithUnit['cy'] := AValue;
     1852end;
     1853
     1854procedure TSVGRadialGradient.SetR(AValue: TFloatWithCSSUnit);
     1855begin
     1856  OrthoAttributeWithUnit['r'] := AValue;
     1857end;
     1858
     1859procedure TSVGRadialGradient.SetFX(AValue: TFloatWithCSSUnit);
     1860begin
     1861  HorizAttributeWithUnit['fx'] := AValue;
     1862end;
     1863
     1864procedure TSVGRadialGradient.SetFY(AValue: TFloatWithCSSUnit);
     1865begin
     1866  VerticalAttributeWithUnit['fy'] := AValue;
     1867end;
     1868
     1869procedure TSVGRadialGradient.SetFR(AValue: TFloatWithCSSUnit);
     1870begin
     1871  HorizAttributeWithUnit['fr'] := AValue;
     1872end;
     1873
     1874constructor TSVGRadialGradient.Create(ADocument: TXMLDocument;
     1875  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1876begin
     1877  inherited Create(ADocument, AUnits, ADataLink);
     1878  Init(ADocument,'radialGradient',AUnits);
     1879end;
     1880
     1881{ TSVGStopGradient }
     1882
     1883function TSVGStopGradient.GetOffset: TFloatWithCSSUnit;
     1884begin
     1885  result := AttributeWithUnit['offset'];
     1886end;
     1887
     1888procedure TSVGStopGradient.SetOffset(AValue: TFloatWithCSSUnit);
     1889begin
     1890  AttributeWithUnit['offset'] := AValue;
     1891end;
     1892
     1893constructor TSVGStopGradient.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     1894  ADataLink: TSVGDataLink);
     1895begin
     1896  inherited Create(ADocument, AUnits, ADataLink);
     1897  Init(ADocument,'stop',AUnits);
     1898end;
     1899
     1900{ TSVGDefine }
     1901
     1902constructor TSVGDefine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
     1903  ADataLink: TSVGDataLink);
     1904begin
     1905  inherited Create(ADocument, AUnits, ADataLink);
     1906  FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
     1907end;
     1908
     1909constructor TSVGDefine.Create(ADocument: TXMLDocument; AElement: TDOMElement;
     1910  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
     1911begin
     1912  inherited Create(ADocument, AElement, AUnits, ADataLink);
     1913  FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
     1914end;
     1915
     1916destructor TSVGDefine.Destroy;
     1917begin
     1918  FreeAndNil(FContent);
     1919  inherited Destroy;
     1920end;
     1921
     1922procedure TSVGDefine.Recompute;
     1923begin
     1924  inherited Recompute;
     1925  FContent.Recompute;
    9071926end;
    9081927
     
    9481967
    9491968constructor TSVGContent.Create(ADocument: TXMLDocument; AElement: TDOMElement;
    950   AUnits: TCSSUnitConverter);
     1969  AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement);
    9511970var cur: TDOMNode;
    9521971begin
    9531972  FDoc := ADocument;
    9541973  FDomElem := AElement;
    955   FElements := TList.Create;
     1974  FDataLink := ADataLink;
     1975  FElements := TFPList.Create;
    9561976  FUnits := AUnits;
    9571977  cur := FDomElem.FirstChild;
     
    9591979  begin
    9601980    if cur is TDOMElement then
    961       FElements.Add(CreateSVGElementFromNode(ADocument,TDOMElement(cur),FUnits));
     1981      FElements.Add(CreateSVGElementFromNode(
     1982        ADocument,TDOMElement(cur),FUnits,ADataLink,ADataParent));
    9621983    cur := cur.NextSibling;
    9631984  end;
     
    9711992  FreeAndNil(FElements);
    9721993  inherited Destroy;
     1994end;
     1995
     1996procedure TSVGContent.Recompute;
     1997var
     1998  i: Integer;
     1999begin
     2000  for i := 0 to ElementCount-1 do
     2001    Element[i].Recompute;
    9732002end;
    9742003
     
    9962025  ): TSVGLine;
    9972026begin
    998   result := TSVGLine.Create(FDoc,Units);
     2027  result := TSVGLine.Create(FDoc,Units,FDataLink);
    9992028  result.x1 := FloatWithCSSUnit(x1,AUnit);
    10002029  result.y1 := FloatWithCSSUnit(y1,AUnit);
     
    10142043  if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
    10152044  begin
    1016     result := TSVGCircle.Create(FDoc,Units);
     2045    result := TSVGCircle.Create(FDoc,Units,FDataLink);
    10172046    result.cx := FloatWithCSSUnit(Units.Convert(cx,AUnit,cuCustom,Units.DpiX),cuCustom);
    10182047    result.cy := FloatWithCSSUnit(Units.Convert(cy,AUnit,cuCustom,Units.DpiY),cuCustom);
     
    10222051  end else
    10232052  begin
    1024     result := TSVGCircle.Create(FDoc,Units);
     2053    result := TSVGCircle.Create(FDoc,Units,FDataLink);
    10252054    result.cx := FloatWithCSSUnit(cx,AUnit);
    10262055    result.cy := FloatWithCSSUnit(cy,AUnit);
     
    10392068  ): TSVGEllipse;
    10402069begin
    1041   result := TSVGEllipse.Create(FDoc,Units);
     2070  result := TSVGEllipse.Create(FDoc,Units,FDataLink);
    10422071  result.cx := FloatWithCSSUnit(cx,AUnit);
    10432072  result.cy := FloatWithCSSUnit(cy,AUnit);
     
    10622091  end else
    10632092  begin
    1064     result := TSVGPath.Create(FDoc,Units);
     2093    result := TSVGPath.Create(FDoc,Units,FDataLink);
    10652094    result.d := data;
    10662095    AppendElement(result);
     
    10722101  if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
    10732102  begin
    1074     result := TSVGPath.Create(FDoc,Units);
     2103    result := TSVGPath.Create(FDoc,Units,FDataLink);
    10752104    result.path.scale(Units.Convert(1,AUnit,cuCustom,Units.DpiX));
    10762105    path.copyTo(result.path);
     
    10792108  end else
    10802109  begin
    1081     result := TSVGPath.Create(FDoc,Units);
     2110    result := TSVGPath.Create(FDoc,Units,FDataLink);
    10822111    result.path.scale(Units.ConvertWidth(1,AUnit,cuCustom));
    10832112    path.copyTo(result.path);
     
    10922121  i: integer;
    10932122begin
    1094   result := TSVGPolypoints.Create(FDoc,FUnits,true);
     2123  result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
    10952124  setlength(pts, length(points) div 2);
    10962125  for i := 0 to high(pts) do
     
    11062135  i: integer;
    11072136begin
    1108   result := TSVGPolypoints.Create(FDoc,FUnits,true);
     2137  result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
    11092138  setlength(pts, length(points));
    11102139  for i := 0 to high(pts) do
     
    11172146  ): TSVGRectangle;
    11182147begin
    1119   result := TSVGRectangle.Create(FDoc,Units);
     2148  result := TSVGRectangle.Create(FDoc,Units,FDataLink);
    11202149  result.x := FloatWithCSSUnit(x,AUnit);
    11212150  result.y := FloatWithCSSUnit(y,AUnit);
     
    11342163  ): TSVGText;
    11352164begin
    1136   result := TSVGText.Create(FDoc,Units);
     2165  result := TSVGText.Create(FDoc,Units,FDataLink);
    11372166  result.x := FloatWithCSSUnit(x,AUnit);
    11382167  result.y := FloatWithCSSUnit(y,AUnit);
     
    11502179  AUnit: TCSSUnit): TSVGRectangle;
    11512180begin
    1152   result := TSVGRectangle.Create(FDoc,Units);
     2181  result := TSVGRectangle.Create(FDoc,Units,FDataLink);
    11532182  result.x := FloatWithCSSUnit(x,AUnit);
    11542183  result.y := FloatWithCSSUnit(y,AUnit);
Note: See TracChangeset for help on using the changeset viewer.