FastReport_2022_VCL/LibD28/frxSVGElement.pas
2024-01-01 16:13:08 +01:00

1001 lines
25 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport VCL }
{ SVG Elements }
{ }
{ Copyright (c) 1998-2021 }
{ by Fast Reports Inc. }
{ }
{******************************************}
unit frxSVGElement;
interface
{$I frx.inc}
uses
Classes, Types,
frxSVGCanvas, frxSVGHelpers, frxSVGComponents, frxCSSStyle, frxSVGAttribute,
frxSVGColor, frxSVGParse;
type
TSVGElementObj = class (TPersistent)
private
FParent: TSVGElementObj;
FItems: TList;
FHostSVG: TSVGElementObj;
FStylesApplyingSequence: TList;
FAttrObj: array[TSVGAttribute] of TSVGAttributeObj;
FIsAttrEnabled: array[TSVGAttribute] of Boolean;
function GetCount: Integer;
function GetItem(const Index: Integer): TSVGElementObj;
function GetIsAttrEnabled(a: TSVGAttribute): Boolean;
procedure SetIsAttrEnabled(a: TSVGAttribute; const Value: Boolean);
function GetAttrObj(a: TSVGAttribute): TSVGAttributeObj;
protected
FID: string;
FRoot: TSVGElementObj;
FElement: TSVGElement;
FInlineStyle: TfrxCSSStyle;
FAttributeStyle: TfrxCSSStyle;
FClasses: TStrings;
FSwitchedOn: Boolean; // to show / hide switch children
FCompleteMatrix: TSVGTransform; // from root
FInnerMatrix: TSVGTransform; // inside nearest svg
FObjBounds: TSingleBounds;
procedure AssignTo(Dest: TPersistent); override;
procedure AssignStylesApplyingSequenceTo(Obj: TSVGElementObj); virtual;
function New(Parent: TSVGElementObj): TSVGElementObj; virtual; abstract;
procedure SelfRoot;
procedure ReadIn(const Node: TfrxSVGXMLItem);
procedure ReadClasses(st: string);
procedure ReadChildren(const Node: TfrxSVGXMLItem);
procedure GetValueFromStyles(aObj: TSVGAttributeObj);
procedure ConstructPath; virtual; // Empty
procedure ClarifyStyleSequences;
procedure ClarifyOwnShorthandProperties; virtual;
procedure ClarifyShorthandProperties;
procedure ConstructPathes;
procedure SwitchChildren; virtual; // Empty
procedure SwitchAll;
procedure TryAddToSequence(StyleName: string); overload;
procedure TryAddToSequence(Style: TfrxCSSStyle); overload;
procedure ConstructStyleSequence;
procedure ConstructAttributes(AElement: TSVGElement);
function GetCanvasClass: TSVGCanvasClass; virtual;
function CalcUnitedChildrenBounds: TSingleBounds;
function CalcSelfBounds: TSingleBounds; virtual; // raise Exception
function IsOpt(eo: TSVGElementOptions): Boolean;
function IsAttrDefault(a: TSVGAttribute): Boolean;
procedure LogStructure(S: string);
public
constructor Create; overload; virtual;
constructor Create(AParent: TSVGElementObj); overload;
destructor Destroy; override;
procedure Clear; virtual;
procedure ClearItems;
procedure ClarifyUses;
function Clone(Parent: TSVGElementObj): TSVGElementObj;
procedure CalculateMatrices; virtual;
procedure ClarifyBounds;
function IsRoot: Boolean; virtual;
function IsNeedsPainting: Boolean;
function SerialNumber: Integer;
procedure CalcMatrix;
function ElementName: string;
function FindByID(const SoughtID: string): TSVGElementObj;
function GetHostViewBoxWidth: Single; virtual;
function GetHostViewBoxHeight: Single; virtual;
function GetHostNormalizedDiagonal: Single; virtual;
function GetWidth: Single; virtual;
function GetHeight: Single; virtual;
function GetBounds: TSingleBounds;
function GetNormalizedDiagonal: Single;
function CalcFillOpacity: Single;
function CalcStrokeOpacity: Single;
function atAlpha(a: TSVGAttribute): Single;
function atIsDefault(a: TSVGAttribute): Boolean;
function atIsPercent(a: TSVGAttribute): Boolean;
function atLength(a: TSVGAttribute; Base: Single = DefaultBase): Single;
function atLengthAuto(a: TSVGAttribute): Single;
procedure atSetLengthAuto(a: TSVGAttribute; Value: Single);
function atLengthInherit(a: TSVGAttribute): Single;
function atLengthList(a: TSVGAttribute): TSingleDynArray;
function atLengthListNoneInherit(a: TSVGAttribute): TSingleDynArray;
function atNumber(a: TSVGAttribute): Single;
function atNumberInherit(a: TSVGAttribute): Single;
function atFontWeight: Single;
function atColorCurrent(a: TSVGAttribute): TSVGColor;
function atColorInherit(a: TSVGAttribute): TSVGColor;
function atSpecificWord(a: TSVGAttribute): TSVGSpecificWord;
function atSpecificWordSet(a: TSVGAttribute): TSVGSpecificWordSet;
function atString(a: TSVGAttribute): string;
function atStringInherit(a: TSVGAttribute): string;
function atURI(a: TSVGAttribute): string;
function atPAR: TSVGPreserveAspectRatio;
function atPaint(a: TSVGAttribute): TSVGPaint;
function atPoints: TSinglePointDynArray;
function atMatrix(a: TSVGAttribute): TSVGTransform;
property Items[const Index: Integer]: TSVGElementObj read GetItem; default;
property Count: Integer read GetCount;
property Element: TSVGElement read FElement;
property Parent: TSVGElementObj read FParent;
property CanvasClass: TSVGCanvasClass read GetCanvasClass;
property ID: string read FID;
property SwitchedOn: Boolean read FSwitchedOn write FSwitchedOn;
property CompleteMatrix: TSVGTransform read FCompleteMatrix;
property InnerMatrix: TSVGTransform read FInnerMatrix;
property IsAttrEnabled[a: TSVGAttribute]: Boolean read GetIsAttrEnabled write SetIsAttrEnabled;
property AttrObj[a: TSVGAttribute]: TSVGAttributeObj read GetAttrObj;
end;
function IsElementByName(Name: string; out Element: TSVGElement): Boolean;
implementation
uses
SysUtils,
Math,
frxSVGBase,
frxSVGPaint,
frxSVGPath;
type
Tel_defs = class(TSVGElementObj)
protected
function New(Parent: TSVGElementObj): TSVGElementObj; override;
public
constructor Create; override;
end;
{ Utility routines }
function IsElementByName(Name: string; out Element: TSVGElement): Boolean;
var
e: TSVGElement;
begin
Result := True;
for e := Low(TSVGElement) to High(TSVGElement) do
if Name = SVGElement[e].Name then
begin
Element := e;
Exit;
end;
Result := False;
end;
{ TSVGElementObj }
procedure TSVGElementObj.AssignStylesApplyingSequenceTo(Obj: TSVGElementObj);
begin
Obj.FStylesApplyingSequence.Clear;
Obj.FStylesApplyingSequence.Assign(FStylesApplyingSequence);
end;
procedure TSVGElementObj.AssignTo(Dest: TPersistent);
var
Obj: TSVGElementObj;
a: TSVGAttribute;
begin
if (Dest is TSVGElementObj) then
begin
Obj := TSVGElementObj(Dest);
Obj.FID := FID;
if Obj.Parent = nil then
FHostSVG := nil
else
FHostSVG := Obj.Parent.FHostSVG;
AssignStylesApplyingSequenceTo(Obj);
Obj.FIsAttrEnabled := FIsAttrEnabled;
for a := Low(a) to High(a) do
if FIsAttrEnabled[a] and not IsAttrDefault(a) then
begin
Obj.FAttrObj[a] := CreateAttribute(Obj, a);
Obj.FAttrObj[a].Assign(AttrObj[a]);
end;
Obj.FInlineStyle.Clear;
Obj.FInlineStyle.Assign(FInlineStyle);
Obj.FAttributeStyle.Clear;
Obj.FAttributeStyle.Assign(FAttributeStyle);
Obj.FClasses.Clear;
Obj.FClasses.Assign(FClasses);
Obj.FSwitchedOn := FSwitchedOn;
Obj.FCompleteMatrix := FCompleteMatrix;
Obj.FInnerMatrix := FInnerMatrix;
Obj.FObjBounds := FObjBounds;
end;
end;
function TSVGElementObj.atAlpha(a: TSVGAttribute): Single;
begin
if IsAttrEnabled[a] then
Result := AttrObj[a].GetAlpha
else
Result := 1.0;
end;
function TSVGElementObj.atColorCurrent(a: TSVGAttribute): TSVGColor;
var
CC: TSVGColorSW;
begin
CC := AttrObj[a].GetColorCurrent;
if CC.SW = svg_currentcolor then
Result := atColorInherit(at_color)
else
Result := ToSVGColor(CC);
end;
function TSVGElementObj.atColorInherit(a: TSVGAttribute): TSVGColor;
var
CI: TSVGColorSW;
begin
CI := AttrObj[a].GetColorInherit;
if CI.SW <> svg_inherit then
Result := ToSVGColor(CI)
else
Result := Parent.atColorInherit(a);
end;
function TSVGElementObj.atFontWeight: Single;
var
FW: TNumberSW;
begin
FW := AttrObj[at_font_weight].GetFontWeight;
if FW.SW = frx_noMater then
Result := FW.Value
else if FW.SW = svg_inherit then
Result := Parent.atFontWeight
else // FW.SW in [svg_bolder, svg_lighter]
Result := RelativeFontWeight(FW.SW, Parent.atFontWeight);
end;
function TSVGElementObj.atIsDefault(a: TSVGAttribute): Boolean;
begin
Result := AttrObj[a].IsDefault;
end;
function TSVGElementObj.atIsPercent(a: TSVGAttribute): Boolean;
begin
Result := AttrObj[a].IsPercent;
end;
function TSVGElementObj.atLength(a: TSVGAttribute; Base: Single = DefaultBase): Single;
begin
Result := AttrObj[a].GetLength(Base);
end;
function TSVGElementObj.atLengthAuto(a: TSVGAttribute): Single;
begin
Result := AttrObj[a].GetLengthAuto;
end;
function TSVGElementObj.atLengthInherit(a: TSVGAttribute): Single;
var
LS: TSVGLengthSW;
begin
LS := AttrObj[a].GetLengthInherit;
if LS.SW <> svg_inherit then
Result := LS.Value
else
Result := Parent.atLengthInherit(a);
end;
function TSVGElementObj.atLengthList(a: TSVGAttribute): TSingleDynArray;
begin
Result := AttrObj[a].GetLengthList;
end;
function TSVGElementObj.atLengthListNoneInherit(a: TSVGAttribute): TSingleDynArray;
begin
if not IsAttrEnabled[a] then
Result := Parent.atLengthListNoneInherit(a)
else
case AttrObj[a].GetLengthListNoneInherit(Result) of
svg_none:
SetLength(Result, 0);
svg_inherit:
Result := Parent.atLengthListNoneInherit(a);
end;
end;
function TSVGElementObj.atMatrix(a: TSVGAttribute): TSVGTransform;
begin
Result := AttrObj[a].GetTransform;
end;
function TSVGElementObj.atNumber(a: TSVGAttribute): Single;
begin
Result := AttrObj[a].GetNumber;
end;
function TSVGElementObj.atNumberInherit(a: TSVGAttribute): Single;
var
NI: TNumberSW;
begin
NI := AttrObj[a].GetNumberSW;
if NI.SW = svg_inherit then
Result := Parent.atNumberInherit(a)
else
Result := NI.Value;
end;
function TSVGElementObj.atPaint(a: TSVGAttribute): TSVGPaint;
var
CP: TSVGPaint;
begin
CP := AttrObj[a].GetPaint;
if CP.SW = svg_currentcolor then
Result := ToSVGPaint(atColorInherit(at_color))
else if CP.SW <> svg_inherit then
Result := CP
else
Result := Parent.atPaint(a);
end;
function TSVGElementObj.atPAR: TSVGPreserveAspectRatio;
begin
Result := AttrObj[at_preserveAspectRatio].GetPreserveAspectRatio;
end;
function TSVGElementObj.atPoints: TSinglePointDynArray;
begin
Result := AttrObj[at_points].GetSinglePointDynSrray;
end;
procedure TSVGElementObj.atSetLengthAuto(a: TSVGAttribute; Value: Single);
begin
AttrObj[a].SetLengthAuto(Value);
end;
function TSVGElementObj.atSpecificWord(a: TSVGAttribute): TSVGSpecificWord;
begin
Result := AttrObj[a].GetSpecificWord;
if Result = svg_inherit then
Result := Parent.atSpecificWord(a);
end;
function TSVGElementObj.atSpecificWordSet(a: TSVGAttribute): TSVGSpecificWordSet;
begin
Result := AttrObj[a].GetSpecificWordSet;
if svg_inherit in Result then
Result := Parent.atSpecificWordSet(a);
end;
function TSVGElementObj.atString(a: TSVGAttribute): string;
begin
Result := AttrObj[a].GetString;
end;
function TSVGElementObj.atStringInherit(a: TSVGAttribute): string;
var
SI: TSVGStringSW;
begin
SI := AttrObj[a].GetStringInherit;
if SI.SW <> svg_inherit then
Result := SI.S
else
Result := Parent.atStringInherit(a);
end;
function TSVGElementObj.atURI(a: TSVGAttribute): string;
begin
Result := AttrObj[a].GetURI;
end;
function TSVGElementObj.CalcFillOpacity: Single;
begin
Result := atAlpha(at_fill_opacity) * atAlpha(at_opacity);
if IsRoot then
Result := Result * TSVGRootObj(Self).ExternalOpacity
else
Result := Result * Parent.CalcFillOpacity;
end;
procedure TSVGElementObj.CalcMatrix;
var
i: Integer;
List: TList;
Obj: TSVGElementObj;
M: TSVGTransform;
begin
List := TList.Create;
try
Obj := Self;
repeat
List.Add(Obj);
Obj := Obj.Parent;
until Obj = nil;
FCompleteMatrix := tmIdentity;
for i := List.Count - 1 downto 0 do
begin
Obj := TSVGElementObj(List[i]);
if Obj is Tel_svg then
begin
M := Tel_svg(Obj).RootMatrix;
FInnerMatrix := tmIdentity;
end
else
begin
M := TSVGElementObj(Obj).atMatrix(at_transform);
FInnerMatrix := tmMultiply(M, FInnerMatrix);
end;
FCompleteMatrix := tmMultiply(M, FCompleteMatrix);
end;
finally
List.Free;
end;
end;
function TSVGElementObj.CalcSelfBounds: TSingleBounds;
begin
raise Exception.Create(ElementName + '.CalcSelfBounds');
end;
function TSVGElementObj.CalcStrokeOpacity: Single;
begin
Result := atAlpha(at_stroke_opacity) * atAlpha(at_opacity);
if IsRoot then
Result := Result * TSVGRootObj(Self).ExternalOpacity
else
Result := Result * Parent.CalcStrokeOpacity;
end;
procedure TSVGElementObj.CalculateMatrices;
var
i: Integer;
begin
if IsOpt(eoMatrix) then
begin
CalcMatrix;
for i := 0 to Count - 1 do
Items[i].CalculateMatrices;
end;
end;
procedure TSVGElementObj.ClarifyBounds;
var
i: Integer;
begin
for i := 0 to Count - 1 do
Items[i].ClarifyBounds;
if IsOpt(eoChildBounds) and (Count > 0) then
begin
FObjBounds := CalcUnitedChildrenBounds;
if IsOpt(eoSelfBounds) then
FObjBounds := SingleBoundsUnion(FObjBounds, CalcSelfBounds)
end
else if IsOpt(eoSelfBounds) then
FObjBounds := CalcSelfBounds;
end;
procedure TSVGElementObj.ClarifyOwnShorthandProperties;
begin
SplitShorthandProperties(FInlineStyle, css_font);
end;
procedure TSVGElementObj.ClarifyShorthandProperties;
var
i: Integer;
begin
ClarifyOwnShorthandProperties;
for i := 0 to Count - 1 do
Items[i].ClarifyOwnShorthandProperties;
end;
procedure TSVGElementObj.ClarifyUses;
var
i: integer;
begin
if FElement = el_use then
Tel_use(Self).Construct;
for i := 0 to Count - 1 do
Items[i].ClarifyUses;
end;
procedure TSVGElementObj.ClarifyStyleSequences;
var
i: Integer;
begin
ConstructStyleSequence;
for i := 0 to Count - 1 do
Items[i].ClarifyStyleSequences;
end;
procedure TSVGElementObj.Clear;
var
a: TSVGAttribute;
begin
ClearItems;
FClasses.Clear;
FInlineStyle.Clear;
FAttributeStyle.Clear;
FStylesApplyingSequence.Clear;
for a := Low(a) to High(a) do
if Assigned(FAttrObj[a]) then
FreeAndNil(FAttrObj[a]);
FID := '';
end;
procedure TSVGElementObj.ClearItems;
begin
while Count > 0 do
Items[Count - 1].Free; // !!
end;
function TSVGElementObj.Clone(Parent: TSVGElementObj): TSVGElementObj;
var
i: Integer;
begin
Result := New(Parent);
Result.Assign(Self);
for i := 0 to Count - 1 do
Items[i].Clone(Result);
end;
procedure TSVGElementObj.ConstructAttributes(AElement: TSVGElement);
var
a: TSVGAttribute;
SumAttributes: TSVGAttributeSet;
begin
FElement := AElement;
SumAttributes := SVGElement[Element].Attributes;
if IsOpt(eoBaseSet) then
SumAttributes := SumAttributes + BaseAttributes;
for a := Low(a) to High(a) do
FIsAttrEnabled[a] := a in SumAttributes;
end;
procedure TSVGElementObj.ConstructPathes;
var
i: Integer;
begin
ConstructPath;
for i := 0 to Count - 1 do
Items[i].ConstructPathes;
end;
procedure TSVGElementObj.ConstructPath;
begin
// Empty
end;
procedure TSVGElementObj.ConstructStyleSequence;
const
UniversalSelectorName = '*';
var
i: Integer;
begin
FStylesApplyingSequence.Clear;
// Inline style (1000)
TryAddToSequence(FInlineStyle);
// Identifiers (100)
if FID <> '' then
begin
TryAddToSequence(ElementName + '#' + FID);
TryAddToSequence('#' + FID);
end;
// Classes (10)
for i := 0 to FClasses.Count - 1 do
TryAddToSequence('.' + FClasses[i]);
// Attribute selectors (10) - skipped for now
// Pseudo-classes (10) - skipped for now
// Tag/Element selectors (1)
TryAddToSequence(ElementName);
// Pseudo-elements (1) - html only, skipped for now
// Universal selector(0)
TryAddToSequence(UniversalSelectorName);
// Attributes
TryAddToSequence(FAttributeStyle);
end;
constructor TSVGElementObj.Create(AParent: TSVGElementObj);
begin
Create;
if AParent <> nil then
begin
FParent := AParent;
Parent.FItems.Add(Self);
FRoot := Parent.FRoot;
if Parent is Tel_svg then
FHostSVG := Parent
else
FHostSVG := Parent.FHostSVG;
end;
end;
constructor TSVGElementObj.Create;
begin
inherited Create;
FParent := nil;
FItems := TList.Create;
FInlineStyle := TfrxCSSStyle.Create;
FAttributeStyle := TfrxCSSStyle.Create;
FClasses := TStringList.Create;
FClasses.Delimiter := ' ';
FStylesApplyingSequence := TList.Create;
FSwitchedOn := True;
end;
destructor TSVGElementObj.Destroy;
begin
Clear;
if Assigned(Parent) then
Parent.FItems.Remove(Self);
FItems.Free;
FInlineStyle.Free;
FAttributeStyle.Free;
FClasses.Free;
FStylesApplyingSequence.Free;
inherited Destroy;
end;
function TSVGElementObj.ElementName: string;
begin
Result := SVGElement[FElement].Name;
end;
function TSVGElementObj.FindByID(const SoughtID: string): TSVGElementObj;
procedure Walk(Obj: TSVGElementObj);
var
i: Integer;
begin
if Obj.FID = SoughtID then
Result := Obj
else
for i := 0 to Obj.Count - 1 do
begin
Walk(Obj[i]);
if Assigned(Result) then
Exit;
end;
end;
begin
Result := nil;
if SoughtID <> '' then
Walk(Self);
end;
function TSVGElementObj.GetAttrObj(a: TSVGAttribute): TSVGAttributeObj;
begin
if not FIsAttrEnabled[a] then
raise Exception.Create('Unsupported: ' + '"' + ElementName + '.' + SVGAttribute[a].Name + '"');
if FAttrObj[a] = nil then
begin
FAttrObj[a] := CreateAttribute(Self, a);
GetValueFromStyles(FAttrObj[a]);
end;
Result := FAttrObj[a];
end;
function TSVGElementObj.GetBounds: TSingleBounds;
begin
if IsOpt(eoChildBounds) or IsOpt(eoSelfBounds) then
Result := FObjBounds
else
raise Exception.Create(ElementName + '.GetBounds');
end;
function TSVGElementObj.GetCanvasClass: TSVGCanvasClass;
begin
Result := TSVGRootObj(FRoot).GetCanvasClass;
end;
function TSVGElementObj.GetCount: Integer;
begin
Result := FItems.Count;
end;
function TSVGElementObj.GetHeight: Single;
begin
Result := FObjBounds.Height;
end;
function TSVGElementObj.GetHostNormalizedDiagonal: Single;
begin
Result := Tel_svg(FHostSVG).GetNormalizedViewBoxDiagonal;
end;
function TSVGElementObj.GetHostViewBoxHeight: Single;
begin
Result := Tel_svg(FHostSVG).GetViewBoxHeight;
end;
function TSVGElementObj.GetHostViewBoxWidth: Single;
begin
Result := Tel_svg(FHostSVG).GetViewBoxWidth;
end;
function TSVGElementObj.GetIsAttrEnabled(a: TSVGAttribute): Boolean;
begin
Result := FIsAttrEnabled[a];
end;
function TSVGElementObj.GetItem(const Index: Integer): TSVGElementObj;
begin
Result := FItems[Index];
end;
function TSVGElementObj.GetNormalizedDiagonal: Single;
begin
Result := Sqrt((Sqr(GetWidth) + Sqr(GetHeight)) / 2);
end;
procedure TSVGElementObj.GetValueFromStyles(aObj: TSVGAttributeObj);
var
i, iLow, iHigh: integer;
begin
if FStylesApplyingSequence.Count > 0 then
begin
iHigh := FStylesApplyingSequence.Count - 1;
if aObj.IsCSS then
iLow := 0
else if FAttributeStyle.Count = 0 then
Exit
else
iLow := iHigh;
for i := iLow to iHigh do
if aObj.IsCanReadSVGValue(TfrxCSSStyle(FStylesApplyingSequence[i])) then
Break;
end;
end;
function TSVGElementObj.GetWidth: Single;
begin
Result := FObjBounds.Width;
end;
function TSVGElementObj.IsOpt(eo: TSVGElementOptions): Boolean;
begin
Result := eo in SVGElement[FElement].Options;
end;
function TSVGElementObj.IsAttrDefault(a: TSVGAttribute): Boolean;
begin
Result := not Assigned(FAttrObj[a]) or FAttrObj[a].IsDefault;
end;
function TSVGElementObj.IsNeedsPainting: Boolean;
begin
Result :=
IsOpt(eoPaint) and
SwitchedOn and
(atSpecificWord(at_display) <> svg_none) and
not ((atSpecificWord(at_visibility) in [svg_collapse, svg_hidden]));
end;
function TSVGElementObj.IsRoot: Boolean;
begin
Result := False;
end;
procedure TSVGElementObj.LogStructure(S: string);
var
i: Integer;
begin
// Log(S + SVGElement[FElement].Name + ':' + FID);
// if Self is TSVGCustomText then
// begin
// Log(S + ' ' + '"' + TSVGCustomText(Self).Text + '"');
// if Length(TSVGCustomText(Self).TextOrigin.X) > 0 then
// Log(frxFloatToStr(TSVGCustomText(Self).TextOrigin.X[0]) + ':' +
// frxFloatToStr(TSVGCustomText(Self).GetCompleteWidth));
// end;
// Log(S + ' ' + tmToStr(TSVGMatrix(Self).PureMatrix));
for i := 0 to Count - 1 do
TSVGElementObj(Items[i]).LogStructure(S + ' ');
end;
procedure TSVGElementObj.ReadChildren(const Node: TfrxSVGXMLItem);
var
i: Integer;
Obj: TSVGElementObj;
Element: TSVGElement;
begin
for i := 0 to Node.ChildNodes.Count - 1 do
if IsElementByName(Node.ChildNodes[i].nodeName, Element) then
begin
Obj := nil;
case Element of
el_a: Obj := Tel_a.Create(Self);
el_circle: Obj := Tel_circle.Create(Self);
el_clipPath: Obj := Tel_clipPath.Create(Self);
el_defs: Obj := Tel_defs.Create(Self);
el_ellipse: Obj := Tel_ellipse.Create(Self);
el_g: Obj := Tel_g.Create(Self);
el_image: Obj := Tel_image.Create(Self);
el_line: Obj := Tel_line.Create(Self);
el_linearGradient: Obj := Tel_linearGradient.Create(Self);
el_path: Obj := Tel_path.Create(Self);
el_polygon: Obj := Tel_polygon.Create(Self);
el_polyline: Obj := Tel_polyline.Create(Self);
el_radialGradient: Obj := Tel_radialGradient.Create(Self);
el_rect: Obj := Tel_Rect.Create(Self);
el_stop: Obj := Tel_stop.Create(Self);
el_style: TSVGRootObj(FRoot).ReadStyle(Node.ChildNodes[i]);
el_svg: Obj := Tel_svg.Create(Self);
el_switch: Obj := Tel_switch.Create(Self);
el_text: Obj := Tel_text.Create(Self);
el_textPath: Obj := Tel_textPath.Create(Self);
el_tspan: Obj := Tel_tspan.Create(Self);
el_PlainText: Obj := TSVGCustomText.CreatePlainText(Self, Node.ChildNodes[i].Text, i, Node.ChildNodes.Count);
el_use: Obj := Tel_use.Create(Self);
end;
if Assigned(Obj) then
Obj.ReadIn(Node.ChildNodes[i]);
end;
end;
procedure TSVGElementObj.ReadClasses(st: string);
var
i: Integer;
begin
FClasses.DelimitedText := st;
for i := FClasses.Count - 1 downto 0 do
begin
FClasses[i] := Trim(FClasses[i]);
if FClasses[i] = '' then
FClasses.Delete(i);
end;
end;
procedure TSVGElementObj.ReadIn(const Node: TfrxSVGXMLItem);
var
i: Integer;
begin
FID := Node.Attributes[SVGAttribute[at_id].Name];
for i := 0 to Node.AttributeNodes.Count - 1 do
with Node.AttributeNodes[i] do
if nodeName = SVGAttribute[at_style].Name then
FInlineStyle.SetValuesFromText(nodeValue)
else if nodeName = SVGAttribute[at_class].Name then
ReadClasses(nodeValue)
else
FAttributeStyle[nodeName] := nodeValue;
if IsOpt(eoHaveChild) then
ReadChildren(Node);
end;
procedure TSVGElementObj.SelfRoot;
begin
FRoot := Self;
end;
function TSVGElementObj.SerialNumber: Integer;
begin
Result := Parent.FItems.IndexOf(Self);
end;
procedure TSVGElementObj.SetIsAttrEnabled(a: TSVGAttribute; const Value: Boolean);
begin
FIsAttrEnabled[a] := Value;
end;
procedure TSVGElementObj.SwitchAll;
var
i: Integer;
begin
SwitchChildren;
for i := 0 to Count - 1 do
if Items[i].FSwitchedOn then
Items[i].SwitchAll;
end;
procedure TSVGElementObj.SwitchChildren;
begin
// Empty
end;
procedure TSVGElementObj.TryAddToSequence(Style: TfrxCSSStyle);
begin
if (Style <> nil) and (Style.Count <> 0) then
FStylesApplyingSequence.Add(Style);
end;
procedure TSVGElementObj.TryAddToSequence(StyleName: string);
var
Style: TfrxCSSStyle;
begin
Style := TSVGRootObj(FRoot).StyleList.GetStyleByName(StyleName);
TryAddToSequence(Style);
end;
function TSVGElementObj.CalcUnitedChildrenBounds;
var
i: Integer;
R: TSingleRect;
begin
R := ToSingleRect(MaxSingle, MaxSingle, -MaxSingle, -MaxSingle);
for i := 0 to Count - 1 do
if Items[i].IsOpt(eoChildBounds) or Items[i].IsOpt(eoSelfBounds) then
R := SingleRectUnion(R, ToSingleRect(Items[i].GetBounds));
if IsSameSingle(R.Left, MaxSingle) or IsSameSingle(R.Top, MaxSingle) then
Result := EmptySingleBounds
else
Result := ToSingleBounds(R);
end;
{ TSVGDefs }
constructor Tel_defs.Create;
begin
inherited Create;
ConstructAttributes(el_defs);
end;
function Tel_defs.New(Parent: TSVGElementObj): TSVGElementObj;
begin
Result := Tel_defs.Create(Parent);
end;
end.