FastReport_2022_VCL/LibD28x64/frxSVGPaint.pas
2024-01-01 16:13:08 +01:00

229 lines
6.2 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport VCL }
{ SVG paint servers }
{ }
{ Copyright (c) 1998-2021 }
{ by Fast Reports Inc. }
{ }
{******************************************}
unit frxSVGPaint;
interface
{$I frx.inc}
uses
Classes, Graphics,
frxSVGCanvas, frxSVGHelpers, frxSVGBase, frxSVGColor,
frxSVGElement, frxSVGComponents;
type
Tel_stop = class(TSVGElementObj)
protected
function New(Parent: TSVGElementObj): TSVGElementObj; override;
public
constructor Create; override;
function GetStopData: TSVGGradientStopData;
end;
TSVGPaintServer = class(TSVGElementObj)
protected
FUser: TSVGElementObj;
public
property User: TSVGElementObj read FUser;
end;
TSVGGradient = class(TSVGPaintServer)
private
FHrefObj: TSVGGradient;
protected
function GetGradientArray(Opacity: Single): TSVGGradientArray; virtual;
procedure SurePercent(AA: array of TSVGAttribute);
public
procedure GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData); virtual;
end;
Tel_linearGradient = class(TSVGGradient)
protected
function New(Parent: TSVGElementObj): TSVGElementObj; override;
public
constructor Create; override;
procedure GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData); override;
end;
Tel_radialGradient = class(TSVGGradient)
protected
function New(Parent: TSVGElementObj): TSVGElementObj; override;
public
constructor Create; override;
procedure GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData); override;
end;
implementation
uses
Math,
frxSVGParse, frxUtils;
{ TSVGStop }
constructor Tel_stop.Create;
begin
inherited Create;
ConstructAttributes(el_stop);
end;
function Tel_stop.GetStopData: TSVGGradientStopData;
begin
Result.SVGColor := atColorCurrent(at_stop_color);
Result.SVGColor.Alpha := Result.SVGColor.Alpha * atAlpha(at_stop_opacity);
Result.Offset := atAlpha(at_offset);
end;
function Tel_stop.New(Parent: TSVGElementObj): TSVGElementObj;
begin
Result := Tel_stop.Create(Parent);
end;
{ TSVGGradient }
function TSVGGradient.GetGradientArray(Opacity: Single): TSVGGradientArray;
function IsFind(const Href: string): Boolean;
begin
if Href = '' then
FHrefObj := Self
else if Href[1] = '#' then
FHrefObj := TSVGGradient(FRoot.FindByID(Copy(Href, 2, MaxInt)));
Result := Assigned(FHrefObj) and (FHrefObj is TSVGGradient) and (FHrefObj.Count > 0);
end;
function Stop(Index: Integer): Tel_stop;
begin
Result := Tel_stop(FHrefObj.Items[Index]);
end;
var
i, AddStart, AddEnd, Len: Integer;
begin
SetLength(Result, 0);
if (FHrefObj = nil) and not IsFind(atString(at_href)) then
Exit;
AddStart := IfInt(Stop(0).GetStopData.Offset > 0, 1);
AddEnd := IfInt(Stop(FHrefObj.Count - 1).GetStopData.Offset < 1, 1);
Len := FHrefObj.Count + AddStart + AddEnd;
SetLength(Result, Len);
for i := 0 to FHrefObj.Count - 1 do
Result[i + AddStart] := Stop(i).GetStopData;
Result[0] := ToSVGGradientStopData(Result[0 + AddStart].SVGColor, 0.0);
Result[Len - 1] := ToSVGGradientStopData(Result[Len - 1 - AddEnd].SVGColor, 1.0);
for i := 0 to FHrefObj.Count - 1 do
Result[i].SVGColor.Alpha := Result[i + AddStart].SVGColor.Alpha * Opacity;
end;
procedure TSVGGradient.GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData);
begin
FUser := User;
GData.Bounds := User.GetBounds;
GData.csu := atSpecificWord(at_gradientUnits);
GData.spreadMethod := atSpecificWord(at_spreadMethod);
if AttrObj[at_Transform].IsDefault then
GData.Matrix := atMatrix(at_gradientTransform)
else
GData.Matrix := atMatrix(at_Transform);
GData.GradientArray := GetGradientArray(Opacity);
end;
procedure TSVGGradient.SurePercent(AA: array of TSVGAttribute);
var
i: integer;
begin
for i := Low(AA) to High(AA) do
AttrObj[AA[i]].PartToPercent;
end;
{ TSVGLinearGradient }
constructor Tel_linearGradient.Create;
begin
inherited Create;
ConstructAttributes(el_linearGradient);
end;
procedure Tel_linearGradient.GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData);
begin
inherited GetGradientData(Opacity, User, GData);
GData.FillerType := ftLinearGradient;
if GData.csu = svg_objectBoundingBox then
SurePercent([at_x1, at_y1, at_x2, at_y2]);
GData.x1 := atLength(at_x1) + IfReal(atIsPercent(at_x1), GData.Bounds.X);
GData.y1 := atLength(at_y1) + IfReal(atIsPercent(at_y1), GData.Bounds.Y);
GData.x2 := atLength(at_x2) + IfReal(atIsPercent(at_x2), GData.Bounds.X);
GData.y2 := atLength(at_y2) + IfReal(atIsPercent(at_y2), GData.Bounds.Y);
end;
function Tel_linearGradient.New(Parent: TSVGElementObj): TSVGElementObj;
begin
Result := Tel_linearGradient.Create(Parent);
end;
{ TSVGRadialGradient }
constructor Tel_radialGradient.Create;
begin
inherited Create;
ConstructAttributes(el_radialGradient);
end;
procedure Tel_radialGradient.GetGradientData(Opacity: Single; const User: TSVGElementObj; out GData: TSVGGradientData);
begin
inherited GetGradientData(Opacity, User, GData);
GData.FillerType := ftRadialGradient;
if GData.csu = svg_objectBoundingBox then
SurePercent([at_cx, at_cy, at_fr, at_fx, at_fy, at_r]);
GData.cx := atLength(at_cx) + IfReal(atIsPercent(at_cx), GData.Bounds.X);
GData.cy := atLength(at_cy) + IfReal(atIsPercent(at_cy), GData.Bounds.Y);
// fx / fy Default: Coincides with the presentational value of cx for the element whether the value for cx was inherited or not.
if atIsDefault(at_fx) then
GData.fx := GData.cx
else
GData.fx := atLength(at_fx) + IfReal(atIsPercent(at_fx), GData.Bounds.X);
if atIsDefault(at_fy) then
GData.fy := GData.cy
else
GData.fy := atLength(at_fy) + IfReal(atIsPercent(at_fx), GData.Bounds.Y);
GData.fr := atLength(at_fr);
GData.r := atLength(at_r);
end;
function Tel_radialGradient.New(Parent: TSVGElementObj): TSVGElementObj;
begin
Result := Tel_radialGradient.Create(Parent);
end;
end.