1 | unit BGRASVGShapes;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, BGRAUnits, laz2_DOM, BGRAPath, BGRABitmapTypes,
|
---|
9 | BGRACanvas2D, BGRASVGType;
|
---|
10 |
|
---|
11 | type
|
---|
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 |
|
---|
39 | { TSVGLine }
|
---|
40 |
|
---|
41 | TSVGLine = class(TSVGElement)
|
---|
42 | private
|
---|
43 | function GetX1: TFloatWithCSSUnit;
|
---|
44 | function GetX2: TFloatWithCSSUnit;
|
---|
45 | function GetY1: TFloatWithCSSUnit;
|
---|
46 | function GetY2: TFloatWithCSSUnit;
|
---|
47 | procedure SetX1(AValue: TFloatWithCSSUnit);
|
---|
48 | procedure SetX2(AValue: TFloatWithCSSUnit);
|
---|
49 | procedure SetY1(AValue: TFloatWithCSSUnit);
|
---|
50 | procedure SetY2(AValue: TFloatWithCSSUnit);
|
---|
51 | protected
|
---|
52 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
53 | public
|
---|
54 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
55 | property x1: TFloatWithCSSUnit read GetX1 write SetX1;
|
---|
56 | property y1: TFloatWithCSSUnit read GetY1 write SetY1;
|
---|
57 | property x2: TFloatWithCSSUnit read GetX2 write SetX2;
|
---|
58 | property y2: TFloatWithCSSUnit read GetY2 write SetY2;
|
---|
59 | end;
|
---|
60 |
|
---|
61 | { TSVGRectangle }
|
---|
62 |
|
---|
63 | TSVGRectangle = class(TSVGElementWithGradient)
|
---|
64 | private
|
---|
65 | function GetX: TFloatWithCSSUnit;
|
---|
66 | function GetY: TFloatWithCSSUnit;
|
---|
67 | function GetWidth: TFloatWithCSSUnit;
|
---|
68 | function GetHeight: TFloatWithCSSUnit;
|
---|
69 | function GetRX: TFloatWithCSSUnit;
|
---|
70 | function GetRY: TFloatWithCSSUnit;
|
---|
71 | procedure SetX(AValue: TFloatWithCSSUnit);
|
---|
72 | procedure SetY(AValue: TFloatWithCSSUnit);
|
---|
73 | procedure SetWidth(AValue: TFloatWithCSSUnit);
|
---|
74 | procedure SetHeight(AValue: TFloatWithCSSUnit);
|
---|
75 | procedure SetRX(AValue: TFloatWithCSSUnit);
|
---|
76 | procedure SetRY(AValue: TFloatWithCSSUnit);
|
---|
77 | protected
|
---|
78 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
79 | public
|
---|
80 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
81 | property x: TFloatWithCSSUnit read GetX write SetX;
|
---|
82 | property y: TFloatWithCSSUnit read GetY write SetY;
|
---|
83 | property width: TFloatWithCSSUnit read GetWidth write SetWidth;
|
---|
84 | property height: TFloatWithCSSUnit read GetHeight write SetHeight;
|
---|
85 | property rx: TFloatWithCSSUnit read GetRX write SetRX;
|
---|
86 | property ry: TFloatWithCSSUnit read GetRY write SetRY;
|
---|
87 | end;
|
---|
88 |
|
---|
89 | { TSVGCircle }
|
---|
90 |
|
---|
91 | TSVGCircle = class(TSVGElementWithGradient)
|
---|
92 | private
|
---|
93 | function GetCX: TFloatWithCSSUnit;
|
---|
94 | function GetCY: TFloatWithCSSUnit;
|
---|
95 | function GetR: TFloatWithCSSUnit;
|
---|
96 | procedure SetCX(AValue: TFloatWithCSSUnit);
|
---|
97 | procedure SetCY(AValue: TFloatWithCSSUnit);
|
---|
98 | procedure SetR(AValue: TFloatWithCSSUnit);
|
---|
99 | protected
|
---|
100 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
101 | public
|
---|
102 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
103 | property cx: TFloatWithCSSUnit read GetCX write SetCX;
|
---|
104 | property cy: TFloatWithCSSUnit read GetCY write SetCY;
|
---|
105 | property r: TFloatWithCSSUnit read GetR write SetR;
|
---|
106 | end;
|
---|
107 |
|
---|
108 | { TSVGEllipse }
|
---|
109 |
|
---|
110 | TSVGEllipse = class(TSVGElementWithGradient)
|
---|
111 | private
|
---|
112 | function GetCX: TFloatWithCSSUnit;
|
---|
113 | function GetCY: TFloatWithCSSUnit;
|
---|
114 | function GetRX: TFloatWithCSSUnit;
|
---|
115 | function GetRY: TFloatWithCSSUnit;
|
---|
116 | procedure SetCX(AValue: TFloatWithCSSUnit);
|
---|
117 | procedure SetCY(AValue: TFloatWithCSSUnit);
|
---|
118 | procedure SetRX(AValue: TFloatWithCSSUnit);
|
---|
119 | procedure SetRY(AValue: TFloatWithCSSUnit);
|
---|
120 | protected
|
---|
121 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
122 | public
|
---|
123 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
124 | property cx: TFloatWithCSSUnit read GetCX write SetCX;
|
---|
125 | property cy: TFloatWithCSSUnit read GetCY write SetCY;
|
---|
126 | property rx: TFloatWithCSSUnit read GetRX write SetRX;
|
---|
127 | property ry: TFloatWithCSSUnit read GetRY write SetRY;
|
---|
128 | end;
|
---|
129 |
|
---|
130 | { TSVGPath }
|
---|
131 |
|
---|
132 | TSVGPath = class(TSVGElementWithGradient)
|
---|
133 | private
|
---|
134 | FPath: TBGRAPath;
|
---|
135 | FBoundingBox: TRectF;
|
---|
136 | FBoundingBoxComputed: boolean;
|
---|
137 | function GetBoundingBoxF: TRectF;
|
---|
138 | function GetPath: TBGRAPath;
|
---|
139 | function GetPathLength: TFloatWithCSSUnit;
|
---|
140 | function GetData: string;
|
---|
141 | procedure SetPathLength(AValue: TFloatWithCSSUnit);
|
---|
142 | procedure SetData(AValue: string);
|
---|
143 | protected
|
---|
144 | function GetDOMElement: TDOMElement; override;
|
---|
145 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
146 | public
|
---|
147 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
148 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
149 | destructor Destroy; override;
|
---|
150 | property d: string read GetData write SetData;
|
---|
151 | property path: TBGRAPath read GetPath;
|
---|
152 | property pathLength: TFloatWithCSSUnit read GetPathLength write SetPathLength;
|
---|
153 | property boundingBoxF: TRectF read GetBoundingBoxF;
|
---|
154 | end;
|
---|
155 |
|
---|
156 | { TSVGPolypoints }
|
---|
157 |
|
---|
158 | TSVGPolypoints = class(TSVGElementWithGradient)
|
---|
159 | private
|
---|
160 | FBoundingBox: TRectF;
|
---|
161 | FBoundingBoxComputed: boolean;
|
---|
162 | function GetBoundingBoxF: TRectF;
|
---|
163 | function GetClosed: boolean;
|
---|
164 | function GetPoints: string;
|
---|
165 | function GetPointsF: ArrayOfTPointF;
|
---|
166 | procedure SetPoints(AValue: string);
|
---|
167 | procedure SetPointsF(AValue: ArrayOfTPointF);
|
---|
168 | procedure ComputeBoundingBox(APoints: ArrayOfTPointF);
|
---|
169 | protected
|
---|
170 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
171 | public
|
---|
172 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink); overload;
|
---|
173 | destructor Destroy; override;
|
---|
174 | property points: string read GetPoints write SetPoints;
|
---|
175 | property pointsF: ArrayOfTPointF read GetPointsF write SetPointsF;
|
---|
176 | property closed: boolean read GetClosed;
|
---|
177 | property boundingBoxF: TRectF read GetBoundingBoxF;
|
---|
178 | end;
|
---|
179 |
|
---|
180 | { TSVGText }
|
---|
181 |
|
---|
182 | TSVGText = class(TSVGElementWithGradient)
|
---|
183 | private
|
---|
184 | function GetFontBold: boolean;
|
---|
185 | function GetFontFamily: string;
|
---|
186 | function GetFontItalic: boolean;
|
---|
187 | function GetFontSize: TFloatWithCSSUnit;
|
---|
188 | function GetFontStyle: string;
|
---|
189 | function GetFontWeight: string;
|
---|
190 | function GetSimpleText: string;
|
---|
191 | function GetTextDecoration: string;
|
---|
192 | function GetX: TFloatWithCSSUnit;
|
---|
193 | function GetY: TFloatWithCSSUnit;
|
---|
194 | procedure SetFontBold(AValue: boolean);
|
---|
195 | procedure SetFontFamily(AValue: string);
|
---|
196 | procedure SetFontItalic(AValue: boolean);
|
---|
197 | procedure SetFontSize(AValue: TFloatWithCSSUnit);
|
---|
198 | procedure SetFontStyle(AValue: string);
|
---|
199 | procedure SetFontWeight(AValue: string);
|
---|
200 | procedure SetSimpleText(AValue: string);
|
---|
201 | procedure SetTextDecoration(AValue: string);
|
---|
202 | procedure SetX(AValue: TFloatWithCSSUnit);
|
---|
203 | procedure SetY(AValue: TFloatWithCSSUnit);
|
---|
204 | protected
|
---|
205 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
206 | public
|
---|
207 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
208 | property x: TFloatWithCSSUnit read GetX write SetX;
|
---|
209 | property y: TFloatWithCSSUnit read GetY write SetY;
|
---|
210 | property SimpleText: string read GetSimpleText write SetSimpleText;
|
---|
211 | property fontSize: TFloatWithCSSUnit read GetFontSize write SetFontSize;
|
---|
212 | property fontFamily: string read GetFontFamily write SetFontFamily;
|
---|
213 | property fontWeight: string read GetFontWeight write SetFontWeight;
|
---|
214 | property fontStyle: string read GetFontStyle write SetFontStyle;
|
---|
215 | property textDecoration: string read GetTextDecoration write SetTextDecoration;
|
---|
216 | property fontBold: boolean read GetFontBold write SetFontBold;
|
---|
217 | property fontItalic: boolean read GetFontItalic write SetFontItalic;
|
---|
218 | end;
|
---|
219 |
|
---|
220 | 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;
|
---|
334 |
|
---|
335 | { TSVGGroup }
|
---|
336 |
|
---|
337 | TSVGGroup = class(TSVGElement)
|
---|
338 | protected
|
---|
339 | FContent: TSVGContent;
|
---|
340 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
---|
341 | public
|
---|
342 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
343 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
344 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
---|
345 | destructor Destroy; override;
|
---|
346 | procedure Recompute; override;
|
---|
347 | property Content: TSVGContent read FContent;
|
---|
348 | 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;
|
---|
381 |
|
---|
382 | { TSVGContent }
|
---|
383 |
|
---|
384 | TSVGContent = class
|
---|
385 | protected
|
---|
386 | FDataLink: TSVGDataLink;
|
---|
387 | FDomElem: TDOMElement;
|
---|
388 | FDoc: TXMLDocument;
|
---|
389 | FElements: TFPList;
|
---|
390 | FUnits: TCSSUnitConverter;
|
---|
391 | procedure AppendElement(AElement: TSVGElement);
|
---|
392 | procedure InsertElementBefore(AElement: TSVGElement; ASuccessor: TSVGElement);
|
---|
393 | function GetElement(AIndex: integer): TSVGElement;
|
---|
394 | function GetElementCount: integer;
|
---|
395 | function GetUnits: TCSSUnitConverter;
|
---|
396 | public
|
---|
397 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter;
|
---|
398 | ADataLink: TSVGDataLink; ADataParent: TSVGElement);
|
---|
399 | destructor Destroy; override;
|
---|
400 | procedure Recompute;
|
---|
401 | procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; AUnit: TCSSUnit); overload;
|
---|
402 | procedure Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); overload;
|
---|
403 | function AppendLine(x1,y1,x2,y2: single; AUnit: TCSSUnit = cuCustom): TSVGLine; overload;
|
---|
404 | function AppendLine(p1,p2: TPointF; AUnit: TCSSUnit = cuCustom): TSVGLine; overload;
|
---|
405 | function AppendCircle(cx,cy,r: single; AUnit: TCSSUnit = cuCustom): TSVGCircle; overload;
|
---|
406 | function AppendCircle(c: TPointF; r: single; AUnit: TCSSUnit = cuCustom): TSVGCircle; overload;
|
---|
407 | function AppendEllipse(cx,cy,rx,ry: single; AUnit: TCSSUnit = cuCustom): TSVGEllipse; overload;
|
---|
408 | function AppendEllipse(c,r: TPointF; AUnit: TCSSUnit = cuCustom): TSVGEllipse; overload;
|
---|
409 | function AppendPath(data: string; AUnit: TCSSUnit = cuCustom): TSVGPath; overload;
|
---|
410 | function AppendPath(path: TBGRAPath; AUnit: TCSSUnit = cuCustom): TSVGPath; overload;
|
---|
411 | function AppendPolygon(const points: array of single; AUnit: TCSSUnit = cuCustom): TSVGPolypoints; overload;
|
---|
412 | function AppendPolygon(const points: array of TPointF; AUnit: TCSSUnit = cuCustom): TSVGPolypoints; overload;
|
---|
413 | function AppendRect(x,y,width,height: single; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
---|
414 | function AppendRect(origin,size: TPointF; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
---|
415 | function AppendText(x,y: single; AText: string; AUnit: TCSSUnit = cuCustom): TSVGText; overload;
|
---|
416 | function AppendText(origin: TPointF; AText: string; AUnit: TCSSUnit = cuCustom): TSVGText; overload;
|
---|
417 | function AppendRoundRect(x,y,width,height,rx,ry: single; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
---|
418 | function AppendRoundRect(origin,size,radius: TPointF; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
---|
419 | property ElementCount: integer read GetElementCount;
|
---|
420 | property Element[AIndex: integer]: TSVGElement read GetElement;
|
---|
421 | property Units: TCSSUnitConverter read GetUnits;
|
---|
422 | end;
|
---|
423 |
|
---|
424 | function GetSVGFactory(ATagName: string): TSVGFactory;
|
---|
425 | function CreateSVGElementFromNode(ADocument: TXMLDocument;
|
---|
426 | AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
|
---|
427 |
|
---|
428 | implementation
|
---|
429 |
|
---|
430 | uses BGRATransform, BGRAGraphics;
|
---|
431 |
|
---|
432 | function GetSVGFactory(ATagName: string): TSVGFactory;
|
---|
433 | var tag: string;
|
---|
434 | begin
|
---|
435 | tag := LowerCase(ATagName);
|
---|
436 | if tag='line' then
|
---|
437 | result := TSVGLine else
|
---|
438 | if tag='rect' then
|
---|
439 | result := TSVGRectangle else
|
---|
440 | if tag='circle' then
|
---|
441 | result := TSVGCircle else
|
---|
442 | if tag='ellipse' then
|
---|
443 | result := TSVGEllipse else
|
---|
444 | if tag='path' then
|
---|
445 | result := TSVGPath else
|
---|
446 | if (tag='polygon') or (tag='polyline') then
|
---|
447 | result := TSVGPolypoints else
|
---|
448 | if tag='text' then
|
---|
449 | 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
|
---|
458 | if tag='g' then
|
---|
459 | result := TSVGGroup else
|
---|
460 | if tag='style' then
|
---|
461 | result := TSVGStyle else
|
---|
462 | result := TSVGElement;
|
---|
463 | end;
|
---|
464 |
|
---|
465 | function CreateSVGElementFromNode(ADocument: TXMLDocument;
|
---|
466 | AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
|
---|
467 | var
|
---|
468 | factory: TSVGFactory;
|
---|
469 | begin
|
---|
470 | factory := GetSVGFactory(AElement.TagName);
|
---|
471 | result := factory.Create(ADocument,AElement,AUnits,ADataLink);
|
---|
472 |
|
---|
473 | ADataLink.Link(result,ADataParent);
|
---|
474 | end;
|
---|
475 |
|
---|
476 | { TSVGElementWithGradient }
|
---|
477 |
|
---|
478 | procedure TSVGElementWithGradient.Initialize;
|
---|
479 | begin
|
---|
480 | inherited Initialize;
|
---|
481 | ResetGradient;
|
---|
482 | end;
|
---|
483 |
|
---|
484 | procedure TSVGElementWithGradient.ResetGradient;
|
---|
485 | begin
|
---|
486 | FGradientElementDefined := false;
|
---|
487 | FGradientElement := nil;
|
---|
488 | FCanvasGradient := nil;
|
---|
489 | end;
|
---|
490 |
|
---|
491 | function TSVGElementWithGradient.FindGradientElement: boolean;
|
---|
492 | var
|
---|
493 | i: integer;
|
---|
494 | s: string;
|
---|
495 | begin
|
---|
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;
|
---|
511 | end;
|
---|
512 |
|
---|
513 | function TSVGElementWithGradient.EvaluatePercentage(fu: TFloatWithCSSUnit): single;
|
---|
514 | begin
|
---|
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;
|
---|
524 | end;
|
---|
525 |
|
---|
526 | function TSVGElementWithGradient.GetGradientElement: TSVGGradient;
|
---|
527 | begin
|
---|
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;
|
---|
536 | end;
|
---|
537 |
|
---|
538 | procedure 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 |
|
---|
558 | var
|
---|
559 | i: integer;
|
---|
560 | begin
|
---|
561 | if not Assigned(GradientElement) then exit;
|
---|
562 | with GradientElement.InheritedGradients do
|
---|
563 | for i:= 0 to Count-1 do
|
---|
564 | AddStopElementFrom(Items[i]);
|
---|
565 | end;
|
---|
566 |
|
---|
567 | procedure TSVGElementWithGradient.CreateCanvasLinearGradient(
|
---|
568 | ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
|
---|
569 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
---|
570 | var p1,p2: TPointF;
|
---|
571 | g: TSVGLinearGradient;
|
---|
572 | m: TAffineMatrix;
|
---|
573 | begin
|
---|
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);
|
---|
600 | end;
|
---|
601 |
|
---|
602 | procedure TSVGElementWithGradient.CreateCanvasRadialGradient(
|
---|
603 | ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient; const origin: TPointF;
|
---|
604 | const w, h: single; AUnit: TCSSUnit);
|
---|
605 | var 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 |
|
---|
625 | begin
|
---|
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;
|
---|
656 | end;
|
---|
657 |
|
---|
658 | procedure TSVGElementWithGradient.InitializeGradient(ACanvas2d: TBGRACanvas2D;
|
---|
659 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
---|
660 | begin
|
---|
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;
|
---|
669 | end;
|
---|
670 |
|
---|
671 | procedure TSVGElementWithGradient.ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
672 | begin
|
---|
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;
|
---|
680 | end;
|
---|
681 |
|
---|
682 | { TSVGText }
|
---|
683 |
|
---|
684 | function TSVGText.GetFontBold: boolean;
|
---|
685 | var valueText: string;
|
---|
686 | begin
|
---|
687 | valueText := trim(fontWeight);
|
---|
688 | result := (valueText = 'bold') or (valueText = 'bolder') or
|
---|
689 | (valueText = '600') or (valueText = '700') or (valueText = '800') or
|
---|
690 | (valueText = '900');
|
---|
691 | end;
|
---|
692 |
|
---|
693 | function TSVGText.GetFontFamily: string;
|
---|
694 | begin
|
---|
695 | result := AttributeOrStyleDef['font-family','Arial'];
|
---|
696 | end;
|
---|
697 |
|
---|
698 | function TSVGText.GetFontItalic: boolean;
|
---|
699 | var valueText: string;
|
---|
700 | begin
|
---|
701 | valueText := trim(fontStyle);
|
---|
702 | result := (valueText = 'oblique') or (valueText = 'italic');
|
---|
703 | end;
|
---|
704 |
|
---|
705 | function TSVGText.GetFontSize: TFloatWithCSSUnit;
|
---|
706 | begin
|
---|
707 | result:= VerticalAttributeOrStyleWithUnit['font-size',FloatWithCSSUnit(12,cuPoint)];
|
---|
708 | end;
|
---|
709 |
|
---|
710 | function TSVGText.GetFontStyle: string;
|
---|
711 | begin
|
---|
712 | result := AttributeOrStyleDef['font-style','normal'];
|
---|
713 | end;
|
---|
714 |
|
---|
715 | function TSVGText.GetFontWeight: string;
|
---|
716 | begin
|
---|
717 | result := AttributeOrStyleDef['font-weight','normal'];
|
---|
718 | end;
|
---|
719 |
|
---|
720 | function TSVGText.GetSimpleText: string;
|
---|
721 | begin
|
---|
722 | result := FDomElem.TextContent;
|
---|
723 | end;
|
---|
724 |
|
---|
725 | function TSVGText.GetTextDecoration: string;
|
---|
726 | begin
|
---|
727 | result := AttributeOrStyleDef['text-decoration','none'];
|
---|
728 | end;
|
---|
729 |
|
---|
730 | function TSVGText.GetX: TFloatWithCSSUnit;
|
---|
731 | begin
|
---|
732 | result := HorizAttributeWithUnit['x'];
|
---|
733 | end;
|
---|
734 |
|
---|
735 | function TSVGText.GetY: TFloatWithCSSUnit;
|
---|
736 | begin
|
---|
737 | result := VerticalAttributeWithUnit['y'];
|
---|
738 | end;
|
---|
739 |
|
---|
740 | procedure TSVGText.SetFontBold(AValue: boolean);
|
---|
741 | begin
|
---|
742 | if AValue then fontWeight:= 'bold' else fontWeight:= 'normal';
|
---|
743 | end;
|
---|
744 |
|
---|
745 | procedure TSVGText.SetFontFamily(AValue: string);
|
---|
746 | begin
|
---|
747 | Attribute['font-family'] := AValue;
|
---|
748 | RemoveStyle('font-family');
|
---|
749 | end;
|
---|
750 |
|
---|
751 | procedure TSVGText.SetFontItalic(AValue: boolean);
|
---|
752 | begin
|
---|
753 | if AValue then fontStyle:= 'italic' else fontStyle:= 'normal';
|
---|
754 | end;
|
---|
755 |
|
---|
756 | procedure TSVGText.SetFontSize(AValue: TFloatWithCSSUnit);
|
---|
757 | begin
|
---|
758 | VerticalAttributeWithUnit['font-size'] := AValue;
|
---|
759 | end;
|
---|
760 |
|
---|
761 | procedure TSVGText.SetFontStyle(AValue: string);
|
---|
762 | begin
|
---|
763 | Attribute['font-style'] := AValue;
|
---|
764 | RemoveStyle('font-style');
|
---|
765 | end;
|
---|
766 |
|
---|
767 | procedure TSVGText.SetFontWeight(AValue: string);
|
---|
768 | begin
|
---|
769 | Attribute['font-weight'] := AValue;
|
---|
770 | RemoveStyle('font-weight');
|
---|
771 | end;
|
---|
772 |
|
---|
773 | procedure TSVGText.SetSimpleText(AValue: string);
|
---|
774 | begin
|
---|
775 | FDomElem.TextContent := AValue;
|
---|
776 | end;
|
---|
777 |
|
---|
778 | procedure TSVGText.SetTextDecoration(AValue: string);
|
---|
779 | begin
|
---|
780 | Attribute['text-decoration'] := AValue;
|
---|
781 | RemoveStyle('text-decoration');
|
---|
782 | end;
|
---|
783 |
|
---|
784 | procedure TSVGText.SetX(AValue: TFloatWithCSSUnit);
|
---|
785 | begin
|
---|
786 | HorizAttributeWithUnit['x'] := AValue;
|
---|
787 | end;
|
---|
788 |
|
---|
789 | procedure TSVGText.SetY(AValue: TFloatWithCSSUnit);
|
---|
790 | begin
|
---|
791 | VerticalAttributeWithUnit['y'] := AValue;
|
---|
792 | end;
|
---|
793 |
|
---|
794 | procedure TSVGText.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
795 | var
|
---|
796 | fs:TFontStyles;
|
---|
797 | vx,vy: single;
|
---|
798 | begin
|
---|
799 | ACanvas2d.beginPath;
|
---|
800 | ACanvas2d.fontEmHeight := Units.ConvertHeight(fontSize,AUnit).value;
|
---|
801 | ACanvas2d.fontName := fontFamily;
|
---|
802 | fs := [];
|
---|
803 | if fontBold then fs += [fsBold];
|
---|
804 | if fontItalic then fs += [fsItalic];
|
---|
805 | ACanvas2d.fontStyle := fs;
|
---|
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 |
|
---|
814 | if not isFillNone then
|
---|
815 | begin
|
---|
816 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
817 | ACanvas2d.fill;
|
---|
818 | end;
|
---|
819 | if not isStrokeNone then
|
---|
820 | begin
|
---|
821 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
822 | ACanvas2d.stroke;
|
---|
823 | end;
|
---|
824 | end;
|
---|
825 |
|
---|
826 | constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
827 | begin
|
---|
828 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
829 | Init(ADocument,'text',AUnits);
|
---|
830 | end;
|
---|
831 |
|
---|
832 | { TSVGGroup }
|
---|
833 |
|
---|
834 | constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
835 | begin
|
---|
836 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
837 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
---|
838 | end;
|
---|
839 |
|
---|
840 | constructor TSVGGroup.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
841 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
842 | begin
|
---|
843 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
---|
844 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
---|
845 | end;
|
---|
846 |
|
---|
847 | destructor TSVGGroup.Destroy;
|
---|
848 | begin
|
---|
849 | FreeAndNil(FContent);
|
---|
850 | inherited Destroy;
|
---|
851 | end;
|
---|
852 |
|
---|
853 | procedure TSVGGroup.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
854 | begin
|
---|
855 | FContent.Draw(ACanvas2d, AUnit);
|
---|
856 | end;
|
---|
857 |
|
---|
858 | procedure TSVGGroup.Recompute;
|
---|
859 | begin
|
---|
860 | inherited Recompute;
|
---|
861 | FContent.Recompute;
|
---|
862 | end;
|
---|
863 |
|
---|
864 | { TSVGStyle }
|
---|
865 |
|
---|
866 | constructor TSVGStyle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
867 | begin
|
---|
868 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
869 | Init(ADocument,'style',AUnits);
|
---|
870 | end;
|
---|
871 |
|
---|
872 | constructor TSVGStyle.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
873 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
874 | begin
|
---|
875 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
---|
876 | Parse(AElement.TextContent);
|
---|
877 | end;
|
---|
878 |
|
---|
879 | procedure TSVGStyle.Initialize;
|
---|
880 | begin
|
---|
881 | inherited Initialize;
|
---|
882 | Clear;
|
---|
883 | end;
|
---|
884 |
|
---|
885 | destructor TSVGStyle.Destroy;
|
---|
886 | begin
|
---|
887 | Clear;
|
---|
888 | inherited Destroy;
|
---|
889 | end;
|
---|
890 |
|
---|
891 | procedure 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 |
|
---|
904 | const
|
---|
905 | EmptyRec: TSVGStyleItem = (name: ''; attribute: '');
|
---|
906 | var
|
---|
907 | i,l,pg: integer;
|
---|
908 | st: String;
|
---|
909 | rec: TSVGStyleItem;
|
---|
910 | begin
|
---|
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;
|
---|
952 | end;
|
---|
953 |
|
---|
954 | function TSVGStyle.IsValidID(const sid: integer): boolean;
|
---|
955 | begin
|
---|
956 | result:= (sid >= 0) and (sid < Length(FStyles));
|
---|
957 | end;
|
---|
958 |
|
---|
959 | function TSVGStyle.GetStyle(const sid: integer): TSVGStyleItem;
|
---|
960 | begin
|
---|
961 | if IsValidID(sid) then
|
---|
962 | result:= FStyles[sid]
|
---|
963 | else
|
---|
964 | raise exception.Create(rsInvalidId);
|
---|
965 | end;
|
---|
966 |
|
---|
967 | procedure TSVGStyle.SetStyle(const sid: integer; sr: TSVGStyleItem);
|
---|
968 | begin
|
---|
969 | if IsValidID(sid) then
|
---|
970 | FStyles[sid]:= sr
|
---|
971 | else
|
---|
972 | raise exception.Create(rsInvalidId);
|
---|
973 | end;
|
---|
974 |
|
---|
975 | function TSVGStyle.Count: Integer;
|
---|
976 | begin
|
---|
977 | result:= Length(FStyles);
|
---|
978 | end;
|
---|
979 |
|
---|
980 | function TSVGStyle.Find(sr: TSVGStyleItem): integer;
|
---|
981 | var
|
---|
982 | i: integer;
|
---|
983 | begin
|
---|
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;
|
---|
993 | end;
|
---|
994 |
|
---|
995 | function TSVGStyle.Find(const AName: string): integer;
|
---|
996 | var
|
---|
997 | i: integer;
|
---|
998 | begin
|
---|
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;
|
---|
1007 | end;
|
---|
1008 |
|
---|
1009 | function TSVGStyle.Add(sr: TSVGStyleItem): integer;
|
---|
1010 | var
|
---|
1011 | l: integer;
|
---|
1012 | begin
|
---|
1013 | l:= Length(FStyles);
|
---|
1014 | SetLength(FStyles,l+1);
|
---|
1015 | FStyles[l]:= sr;
|
---|
1016 | result:= l;
|
---|
1017 | end;
|
---|
1018 |
|
---|
1019 | procedure TSVGStyle.Remove(sr: TSVGStyleItem);
|
---|
1020 | var
|
---|
1021 | l,p: integer;
|
---|
1022 | begin
|
---|
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;
|
---|
1031 | end;
|
---|
1032 |
|
---|
1033 | procedure TSVGStyle.Clear;
|
---|
1034 | begin
|
---|
1035 | SetLength(FStyles,0);
|
---|
1036 | end;
|
---|
1037 |
|
---|
1038 | procedure TSVGStyle.ReParse;
|
---|
1039 | begin
|
---|
1040 | Parse(FDomElem.TextContent);
|
---|
1041 | end;
|
---|
1042 |
|
---|
1043 | { TSVGRectangle }
|
---|
1044 |
|
---|
1045 | function TSVGRectangle.GetX: TFloatWithCSSUnit;
|
---|
1046 | begin
|
---|
1047 | result := HorizAttributeWithUnit['x'];
|
---|
1048 | end;
|
---|
1049 |
|
---|
1050 | function TSVGRectangle.GetY: TFloatWithCSSUnit;
|
---|
1051 | begin
|
---|
1052 | result := VerticalAttributeWithUnit['y'];
|
---|
1053 | end;
|
---|
1054 |
|
---|
1055 | function TSVGRectangle.GetWidth: TFloatWithCSSUnit;
|
---|
1056 | begin
|
---|
1057 | result := HorizAttributeWithUnit['width'];
|
---|
1058 | end;
|
---|
1059 |
|
---|
1060 | function TSVGRectangle.GetHeight: TFloatWithCSSUnit;
|
---|
1061 | begin
|
---|
1062 | result := VerticalAttributeWithUnit['height'];
|
---|
1063 | end;
|
---|
1064 |
|
---|
1065 | function TSVGRectangle.GetRX: TFloatWithCSSUnit;
|
---|
1066 | begin
|
---|
1067 | result := HorizAttributeWithUnit['rx'];
|
---|
1068 | end;
|
---|
1069 |
|
---|
1070 | function TSVGRectangle.GetRY: TFloatWithCSSUnit;
|
---|
1071 | begin
|
---|
1072 | result := VerticalAttributeWithUnit['ry'];
|
---|
1073 | end;
|
---|
1074 |
|
---|
1075 | procedure TSVGRectangle.SetX(AValue: TFloatWithCSSUnit);
|
---|
1076 | begin
|
---|
1077 | HorizAttributeWithUnit['x'] := AValue;
|
---|
1078 | end;
|
---|
1079 |
|
---|
1080 | procedure TSVGRectangle.SetY(AValue: TFloatWithCSSUnit);
|
---|
1081 | begin
|
---|
1082 | VerticalAttributeWithUnit['y'] := AValue;
|
---|
1083 | end;
|
---|
1084 |
|
---|
1085 | procedure TSVGRectangle.SetWidth(AValue: TFloatWithCSSUnit);
|
---|
1086 | begin
|
---|
1087 | HorizAttributeWithUnit['width'] := AValue;
|
---|
1088 | end;
|
---|
1089 |
|
---|
1090 | procedure TSVGRectangle.SetHeight(AValue: TFloatWithCSSUnit);
|
---|
1091 | begin
|
---|
1092 | VerticalAttributeWithUnit['height'] := AValue;
|
---|
1093 | end;
|
---|
1094 |
|
---|
1095 | procedure TSVGRectangle.SetRX(AValue: TFloatWithCSSUnit);
|
---|
1096 | begin
|
---|
1097 | HorizAttributeWithUnit['rx'] := AValue;
|
---|
1098 | end;
|
---|
1099 |
|
---|
1100 | procedure TSVGRectangle.SetRY(AValue: TFloatWithCSSUnit);
|
---|
1101 | begin
|
---|
1102 | VerticalAttributeWithUnit['ry'] := AValue;
|
---|
1103 | end;
|
---|
1104 |
|
---|
1105 | constructor TSVGRectangle.Create(ADocument: TXMLDocument;
|
---|
1106 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1107 | begin
|
---|
1108 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1109 | Init(ADocument,'rect',AUnits);
|
---|
1110 | end;
|
---|
1111 |
|
---|
1112 | procedure TSVGRectangle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1113 | var
|
---|
1114 | vx,vy,vw,vh: Single;
|
---|
1115 | begin
|
---|
1116 | if not isStrokeNone or not isFillNone then
|
---|
1117 | 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;
|
---|
1122 | ACanvas2d.beginPath;
|
---|
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);
|
---|
1127 | if not isFillNone then
|
---|
1128 | begin
|
---|
1129 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
1130 | ACanvas2d.fill;
|
---|
1131 | end;
|
---|
1132 | if not isStrokeNone then
|
---|
1133 | begin
|
---|
1134 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1135 | ACanvas2d.stroke;
|
---|
1136 | end;
|
---|
1137 | end;
|
---|
1138 | end;
|
---|
1139 |
|
---|
1140 | { TSVGPolypoints }
|
---|
1141 |
|
---|
1142 | function TSVGPolypoints.GetClosed: boolean;
|
---|
1143 | begin
|
---|
1144 | result := FDomElem.TagName = 'polygon';
|
---|
1145 | end;
|
---|
1146 |
|
---|
1147 | function TSVGPolypoints.GetBoundingBoxF: TRectF;
|
---|
1148 | begin
|
---|
1149 | if not FBoundingBoxComputed then
|
---|
1150 | ComputeBoundingBox(pointsF);
|
---|
1151 | result := FBoundingBox;
|
---|
1152 | end;
|
---|
1153 |
|
---|
1154 | function TSVGPolypoints.GetPoints: string;
|
---|
1155 | begin
|
---|
1156 | result := Attribute['points'];
|
---|
1157 | end;
|
---|
1158 |
|
---|
1159 | function TSVGPolypoints.GetPointsF: ArrayOfTPointF;
|
---|
1160 | var parser: TSVGParser;
|
---|
1161 | nbcoord,i: integer;
|
---|
1162 | begin
|
---|
1163 | parser:=TSVGParser.Create(points);
|
---|
1164 | nbcoord := 0;
|
---|
1165 | repeat
|
---|
1166 | parser.ParseFloat;
|
---|
1167 | if not parser.NumberError then
|
---|
1168 | inc(nbcoord);
|
---|
1169 | until parser.NumberError or parser.Done;
|
---|
1170 | parser.ClearError;
|
---|
1171 | setlength(Result,nbcoord div 2);
|
---|
1172 | parser.Position := 1;
|
---|
1173 | for i := 0 to high(result) do
|
---|
1174 | begin
|
---|
1175 | result[i].x := parser.ParseFloat;
|
---|
1176 | result[i].y := parser.ParseFloat;
|
---|
1177 | end;
|
---|
1178 | parser.Free;
|
---|
1179 | end;
|
---|
1180 |
|
---|
1181 | procedure TSVGPolypoints.SetPoints(AValue: string);
|
---|
1182 | begin
|
---|
1183 | Attribute['points'] := AValue;
|
---|
1184 | end;
|
---|
1185 |
|
---|
1186 | procedure TSVGPolypoints.SetPointsF(AValue: ArrayOfTPointF);
|
---|
1187 | var s: string;
|
---|
1188 | i: integer;
|
---|
1189 | begin
|
---|
1190 | s:= '';
|
---|
1191 | for i := 0 to high(AValue) do
|
---|
1192 | begin
|
---|
1193 | if s <> '' then s += ' ';
|
---|
1194 | with AValue[i] do
|
---|
1195 | s += TCSSUnitConverter.formatValue(x)+' '+TCSSUnitConverter.formatValue(y);
|
---|
1196 | end;
|
---|
1197 | points := s;
|
---|
1198 | ComputeBoundingBox(AValue);
|
---|
1199 | end;
|
---|
1200 |
|
---|
1201 | procedure TSVGPolypoints.ComputeBoundingBox(APoints: ArrayOfTPointF);
|
---|
1202 | var
|
---|
1203 | i: Integer;
|
---|
1204 | begin
|
---|
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;
|
---|
1227 | end;
|
---|
1228 |
|
---|
1229 | constructor TSVGPolypoints.Create(ADocument: TXMLDocument;
|
---|
1230 | AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink);
|
---|
1231 | begin
|
---|
1232 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1233 | if AClosed then
|
---|
1234 | Init(ADocument, 'polygon', AUnits)
|
---|
1235 | else
|
---|
1236 | Init(ADocument, 'polyline', AUnits);
|
---|
1237 | end;
|
---|
1238 |
|
---|
1239 | destructor TSVGPolypoints.Destroy;
|
---|
1240 | begin
|
---|
1241 | inherited Destroy;
|
---|
1242 | end;
|
---|
1243 |
|
---|
1244 | procedure TSVGPolypoints.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1245 | var
|
---|
1246 | prevMatrix: TAffineMatrix;
|
---|
1247 | pts: ArrayOfTPointF;
|
---|
1248 | begin
|
---|
1249 | if isFillNone and isStrokeNone then exit;
|
---|
1250 | if AUnit <> cuCustom then
|
---|
1251 | begin
|
---|
1252 | prevMatrix := ACanvas2d.matrix;
|
---|
1253 | ACanvas2d.scale(Units.ConvertWidth(1,cuCustom,AUnit),
|
---|
1254 | Units.ConvertHeight(1,cuCustom,AUnit));
|
---|
1255 | InternalDraw(ACanvas2d, cuCustom);
|
---|
1256 | ACanvas2d.matrix:= prevMatrix;
|
---|
1257 | end else
|
---|
1258 | begin
|
---|
1259 | ACanvas2d.beginPath;
|
---|
1260 | pts := pointsF;
|
---|
1261 | ACanvas2d.polylineTo(pts);
|
---|
1262 | 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 |
|
---|
1268 | if not isFillNone then
|
---|
1269 | begin
|
---|
1270 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
1271 | ACanvas2d.fill;
|
---|
1272 | end;
|
---|
1273 | if not isStrokeNone then
|
---|
1274 | begin
|
---|
1275 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1276 | ACanvas2d.stroke;
|
---|
1277 | end;
|
---|
1278 | end;
|
---|
1279 | end;
|
---|
1280 |
|
---|
1281 | { TSVGPath }
|
---|
1282 |
|
---|
1283 | function TSVGPath.GetPathLength: TFloatWithCSSUnit;
|
---|
1284 | begin
|
---|
1285 | result := OrthoAttributeWithUnit['pathLength'];
|
---|
1286 | end;
|
---|
1287 |
|
---|
1288 | function TSVGPath.GetPath: TBGRAPath;
|
---|
1289 | begin
|
---|
1290 | if FPath = nil then
|
---|
1291 | FPath := TBGRAPath.Create(Attribute['d']);
|
---|
1292 | result := FPath;
|
---|
1293 | end;
|
---|
1294 |
|
---|
1295 | function TSVGPath.GetBoundingBoxF: TRectF;
|
---|
1296 | begin
|
---|
1297 | if not FBoundingBoxComputed then
|
---|
1298 | begin
|
---|
1299 | FBoundingBox := path.GetBounds;
|
---|
1300 | FBoundingBoxComputed := true;
|
---|
1301 | end;
|
---|
1302 | result := FBoundingBox;
|
---|
1303 | end;
|
---|
1304 |
|
---|
1305 | function TSVGPath.GetData: string;
|
---|
1306 | begin
|
---|
1307 | if FPath = nil then
|
---|
1308 | result := Attribute['d']
|
---|
1309 | else
|
---|
1310 | result := FPath.SvgString;
|
---|
1311 | end;
|
---|
1312 |
|
---|
1313 | procedure TSVGPath.SetPathLength(AValue: TFloatWithCSSUnit);
|
---|
1314 | begin
|
---|
1315 | OrthoAttributeWithUnit['pathLength'] := AValue;
|
---|
1316 | end;
|
---|
1317 |
|
---|
1318 | procedure TSVGPath.SetData(AValue: string);
|
---|
1319 | begin
|
---|
1320 | if FPath = nil then
|
---|
1321 | Attribute['d'] := AValue
|
---|
1322 | else
|
---|
1323 | FPath.SvgString := AValue;
|
---|
1324 | FBoundingBoxComputed := false;
|
---|
1325 | end;
|
---|
1326 |
|
---|
1327 | function TSVGPath.GetDOMElement: TDOMElement;
|
---|
1328 | begin
|
---|
1329 | if FPath <> nil then Attribute['d'] := FPath.SvgString;
|
---|
1330 | Result:=inherited GetDOMElement;
|
---|
1331 | end;
|
---|
1332 |
|
---|
1333 | constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1334 | begin
|
---|
1335 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1336 | Init(ADocument,'path',AUnits);
|
---|
1337 | FPath := nil;
|
---|
1338 | FBoundingBoxComputed := false;
|
---|
1339 | FBoundingBox := rectF(0,0,0,0);
|
---|
1340 | end;
|
---|
1341 |
|
---|
1342 | constructor TSVGPath.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
1343 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1344 | begin
|
---|
1345 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
---|
1346 | Init(ADocument, AElement, AUnits);
|
---|
1347 | FPath := nil;
|
---|
1348 | FBoundingBoxComputed := false;
|
---|
1349 | FBoundingBox := rectF(0,0,0,0);
|
---|
1350 | end;
|
---|
1351 |
|
---|
1352 | destructor TSVGPath.Destroy;
|
---|
1353 | begin
|
---|
1354 | FreeAndNil(FPath);
|
---|
1355 | inherited Destroy;
|
---|
1356 | end;
|
---|
1357 |
|
---|
1358 | procedure TSVGPath.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1359 | var
|
---|
1360 | prevMatrix: TAffineMatrix;
|
---|
1361 | begin
|
---|
1362 | if isFillNone and isStrokeNone then exit;
|
---|
1363 | if AUnit <> cuCustom then
|
---|
1364 | begin
|
---|
1365 | prevMatrix := ACanvas2d.matrix;
|
---|
1366 | ACanvas2d.scale(Units.ConvertWidth(1,cuCustom,AUnit),
|
---|
1367 | Units.ConvertHeight(1,cuCustom,AUnit));
|
---|
1368 | InternalDraw(ACanvas2d, cuCustom);
|
---|
1369 | ACanvas2d.matrix:= prevMatrix;
|
---|
1370 | end else
|
---|
1371 | begin
|
---|
1372 | 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);
|
---|
1377 | if not isFillNone then
|
---|
1378 | begin
|
---|
1379 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
1380 | ACanvas2d.fill;
|
---|
1381 | end;
|
---|
1382 | if not isStrokeNone then
|
---|
1383 | begin
|
---|
1384 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1385 | ACanvas2d.stroke;
|
---|
1386 | end;
|
---|
1387 | end;
|
---|
1388 | end;
|
---|
1389 |
|
---|
1390 | { TSVGEllipse }
|
---|
1391 |
|
---|
1392 | function TSVGEllipse.GetCX: TFloatWithCSSUnit;
|
---|
1393 | begin
|
---|
1394 | result := HorizAttributeWithUnit['cx'];
|
---|
1395 | end;
|
---|
1396 |
|
---|
1397 | function TSVGEllipse.GetCY: TFloatWithCSSUnit;
|
---|
1398 | begin
|
---|
1399 | result := VerticalAttributeWithUnit['cy'];
|
---|
1400 | end;
|
---|
1401 |
|
---|
1402 | function TSVGEllipse.GetRX: TFloatWithCSSUnit;
|
---|
1403 | begin
|
---|
1404 | result := HorizAttributeWithUnit['rx'];
|
---|
1405 | end;
|
---|
1406 |
|
---|
1407 | function TSVGEllipse.GetRY: TFloatWithCSSUnit;
|
---|
1408 | begin
|
---|
1409 | result := VerticalAttributeWithUnit['ry'];
|
---|
1410 | end;
|
---|
1411 |
|
---|
1412 | procedure TSVGEllipse.SetCX(AValue: TFloatWithCSSUnit);
|
---|
1413 | begin
|
---|
1414 | HorizAttributeWithUnit['cx'] := AValue;
|
---|
1415 | end;
|
---|
1416 |
|
---|
1417 | procedure TSVGEllipse.SetCY(AValue: TFloatWithCSSUnit);
|
---|
1418 | begin
|
---|
1419 | VerticalAttributeWithUnit['cy'] := AValue;
|
---|
1420 | end;
|
---|
1421 |
|
---|
1422 | procedure TSVGEllipse.SetRX(AValue: TFloatWithCSSUnit);
|
---|
1423 | begin
|
---|
1424 | HorizAttributeWithUnit['rx'] := AValue;
|
---|
1425 | end;
|
---|
1426 |
|
---|
1427 | procedure TSVGEllipse.SetRY(AValue: TFloatWithCSSUnit);
|
---|
1428 | begin
|
---|
1429 | VerticalAttributeWithUnit['ry'] := AValue;
|
---|
1430 | end;
|
---|
1431 |
|
---|
1432 | constructor TSVGEllipse.Create(ADocument: TXMLDocument;
|
---|
1433 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1434 | begin
|
---|
1435 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1436 | Init(ADocument,'ellipse',AUnits);
|
---|
1437 | end;
|
---|
1438 |
|
---|
1439 | procedure TSVGEllipse.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1440 | var
|
---|
1441 | vcx,vcy,vrx,vry: Single;
|
---|
1442 | begin
|
---|
1443 | if not isFillNone or not isStrokeNone then
|
---|
1444 | 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;
|
---|
1449 | ACanvas2d.beginPath;
|
---|
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);
|
---|
1453 | if not isFillNone then
|
---|
1454 | begin
|
---|
1455 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
1456 | ACanvas2d.fill;
|
---|
1457 | end;
|
---|
1458 | if not isStrokeNone then
|
---|
1459 | begin
|
---|
1460 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1461 | ACanvas2d.stroke;
|
---|
1462 | end;
|
---|
1463 | end;
|
---|
1464 | end;
|
---|
1465 |
|
---|
1466 | { TSVGCircle }
|
---|
1467 |
|
---|
1468 | function TSVGCircle.GetCX: TFloatWithCSSUnit;
|
---|
1469 | begin
|
---|
1470 | result := HorizAttributeWithUnit['cx'];
|
---|
1471 | end;
|
---|
1472 |
|
---|
1473 | function TSVGCircle.GetCY: TFloatWithCSSUnit;
|
---|
1474 | begin
|
---|
1475 | result := VerticalAttributeWithUnit['cy'];
|
---|
1476 | end;
|
---|
1477 |
|
---|
1478 | function TSVGCircle.GetR: TFloatWithCSSUnit;
|
---|
1479 | begin
|
---|
1480 | result := OrthoAttributeWithUnit['r'];
|
---|
1481 | end;
|
---|
1482 |
|
---|
1483 | procedure TSVGCircle.SetCX(AValue: TFloatWithCSSUnit);
|
---|
1484 | begin
|
---|
1485 | HorizAttributeWithUnit['cx'] := AValue;
|
---|
1486 | end;
|
---|
1487 |
|
---|
1488 | procedure TSVGCircle.SetCY(AValue: TFloatWithCSSUnit);
|
---|
1489 | begin
|
---|
1490 | VerticalAttributeWithUnit['cy'] := AValue;
|
---|
1491 | end;
|
---|
1492 |
|
---|
1493 | procedure TSVGCircle.SetR(AValue: TFloatWithCSSUnit);
|
---|
1494 | begin
|
---|
1495 | OrthoAttributeWithUnit['r'] := AValue;
|
---|
1496 | end;
|
---|
1497 |
|
---|
1498 | constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1499 | begin
|
---|
1500 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1501 | Init(ADocument,'circle',AUnits);
|
---|
1502 | end;
|
---|
1503 |
|
---|
1504 | procedure TSVGCircle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1505 | var
|
---|
1506 | vcx,vcy,vr: Single;
|
---|
1507 | begin
|
---|
1508 | if not isFillNone or not isStrokeNone then
|
---|
1509 | begin
|
---|
1510 | vcx:= Units.ConvertWidth(cx,AUnit).value;
|
---|
1511 | vcy:= Units.ConvertHeight(cy,AUnit).value;
|
---|
1512 | vr:= Units.ConvertWidth(r,AUnit).value;
|
---|
1513 | ACanvas2d.beginPath;
|
---|
1514 | ACanvas2d.circle(vcx,vcy,vr);
|
---|
1515 | if Assigned(GradientElement) then
|
---|
1516 | InitializeGradient(ACanvas2d, PointF(vcx-vr,vcy-vr),vr*2,vr*2,AUnit);
|
---|
1517 | if not isFillNone then
|
---|
1518 | begin
|
---|
1519 | ApplyFillStyle(ACanvas2D,AUnit);
|
---|
1520 | ACanvas2d.fill;
|
---|
1521 | end;
|
---|
1522 | if not isStrokeNone then
|
---|
1523 | begin
|
---|
1524 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1525 | ACanvas2d.stroke;
|
---|
1526 | end;
|
---|
1527 | end;
|
---|
1528 | end;
|
---|
1529 |
|
---|
1530 | { TSVGLine }
|
---|
1531 |
|
---|
1532 | function TSVGLine.GetX1: TFloatWithCSSUnit;
|
---|
1533 | begin
|
---|
1534 | result := HorizAttributeWithUnit['x1'];
|
---|
1535 | end;
|
---|
1536 |
|
---|
1537 | function TSVGLine.GetX2: TFloatWithCSSUnit;
|
---|
1538 | begin
|
---|
1539 | result := HorizAttributeWithUnit['x2'];
|
---|
1540 | end;
|
---|
1541 |
|
---|
1542 | function TSVGLine.GetY1: TFloatWithCSSUnit;
|
---|
1543 | begin
|
---|
1544 | result := VerticalAttributeWithUnit['y1'];
|
---|
1545 | end;
|
---|
1546 |
|
---|
1547 | function TSVGLine.GetY2: TFloatWithCSSUnit;
|
---|
1548 | begin
|
---|
1549 | result := VerticalAttributeWithUnit['y2'];
|
---|
1550 | end;
|
---|
1551 |
|
---|
1552 | procedure TSVGLine.SetX1(AValue: TFloatWithCSSUnit);
|
---|
1553 | begin
|
---|
1554 | HorizAttributeWithUnit['x1'] := AValue;
|
---|
1555 | end;
|
---|
1556 |
|
---|
1557 | procedure TSVGLine.SetX2(AValue: TFloatWithCSSUnit);
|
---|
1558 | begin
|
---|
1559 | HorizAttributeWithUnit['x2'] := AValue;
|
---|
1560 | end;
|
---|
1561 |
|
---|
1562 | procedure TSVGLine.SetY1(AValue: TFloatWithCSSUnit);
|
---|
1563 | begin
|
---|
1564 | VerticalAttributeWithUnit['y1'] := AValue;
|
---|
1565 | end;
|
---|
1566 |
|
---|
1567 | procedure TSVGLine.SetY2(AValue: TFloatWithCSSUnit);
|
---|
1568 | begin
|
---|
1569 | VerticalAttributeWithUnit['y2'] := AValue;
|
---|
1570 | end;
|
---|
1571 |
|
---|
1572 | constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1573 | begin
|
---|
1574 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1575 | Init(ADocument,'line',AUnits);
|
---|
1576 | end;
|
---|
1577 |
|
---|
1578 | procedure TSVGLine.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
1579 | begin
|
---|
1580 | if not isStrokeNone then
|
---|
1581 | begin
|
---|
1582 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
---|
1583 | ACanvas2d.beginPath;
|
---|
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);
|
---|
1586 | ACanvas2d.stroke;
|
---|
1587 | end;
|
---|
1588 | end;
|
---|
1589 |
|
---|
1590 | { TSVGGradient } //##
|
---|
1591 |
|
---|
1592 | function TSVGGradient.GetHRef: string;
|
---|
1593 | begin
|
---|
1594 | result := Attribute['xlink:href'];
|
---|
1595 | if result = '' then
|
---|
1596 | result := Attribute['href'];//(Note: specific for svg 2)
|
---|
1597 | end;
|
---|
1598 |
|
---|
1599 | function TSVGGradient.GetUseObjectBoundingBox: boolean;
|
---|
1600 | begin
|
---|
1601 | result := (gradientUnits = 'objectBoundingBox');
|
---|
1602 | end;
|
---|
1603 |
|
---|
1604 | procedure TSVGGradient.SetGradientTransform(AValue: string);
|
---|
1605 | begin
|
---|
1606 | Attribute['gradientTransform'] := AValue;
|
---|
1607 | end;
|
---|
1608 |
|
---|
1609 | function TSVGGradient.GetGradientUnits: string;
|
---|
1610 | begin
|
---|
1611 | result := AttributeDef['gradientUnits','objectBoundingBox'];
|
---|
1612 | end;
|
---|
1613 |
|
---|
1614 | function TSVGGradient.GetGradientTransform: string;
|
---|
1615 | begin
|
---|
1616 | result := Attribute['gradientTransform'];
|
---|
1617 | end;
|
---|
1618 |
|
---|
1619 | function TSVGGradient.GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
|
---|
1620 | var parser: TSVGParser;
|
---|
1621 | s: string;
|
---|
1622 | begin
|
---|
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);
|
---|
1634 | end;
|
---|
1635 |
|
---|
1636 | procedure TSVGGradient.SetGradientUnits(AValue: string);
|
---|
1637 | begin
|
---|
1638 | Attribute['gradientUnits'] := AValue;
|
---|
1639 | end;
|
---|
1640 |
|
---|
1641 | procedure TSVGGradient.SetHRef(AValue: string);
|
---|
1642 | begin
|
---|
1643 | Attribute['xlink:href'] := AValue;
|
---|
1644 | end;
|
---|
1645 |
|
---|
1646 | constructor TSVGGradient.Create(ADocument: TXMLDocument;
|
---|
1647 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1648 | begin
|
---|
1649 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1650 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
---|
1651 | end;
|
---|
1652 |
|
---|
1653 | function TSVGGradient.HRefToGradientID(const AValue: string): string;
|
---|
1654 | var
|
---|
1655 | l: integer;
|
---|
1656 | begin
|
---|
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);
|
---|
1663 | end;
|
---|
1664 |
|
---|
1665 | function TSVGGradient.FindGradientRef(const AGradientID: string): integer;
|
---|
1666 | var
|
---|
1667 | i: integer;
|
---|
1668 | begin
|
---|
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;
|
---|
1677 | end;
|
---|
1678 |
|
---|
1679 | procedure TSVGGradient.Initialize;
|
---|
1680 | begin
|
---|
1681 | inherited;
|
---|
1682 | InheritedGradients:= TSVGElementList.Create;
|
---|
1683 | end;
|
---|
1684 |
|
---|
1685 | function TSVGGradient.GetInheritedAttribute(AValue: string;
|
---|
1686 | AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
|
---|
1687 | var
|
---|
1688 | i: integer;
|
---|
1689 | el: TSVGGradient;
|
---|
1690 | invalidDef: TFloatWithCSSUnit;
|
---|
1691 | begin
|
---|
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;
|
---|
1714 | end;
|
---|
1715 |
|
---|
1716 | constructor TSVGGradient.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
1717 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1718 | begin
|
---|
1719 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
---|
1720 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
---|
1721 | end;
|
---|
1722 |
|
---|
1723 | destructor TSVGGradient.Destroy;
|
---|
1724 | begin
|
---|
1725 | FreeAndNil(FContent);
|
---|
1726 | FreeAndNil(InheritedGradients);
|
---|
1727 | inherited Destroy;
|
---|
1728 | end;
|
---|
1729 |
|
---|
1730 | procedure TSVGGradient.Recompute;
|
---|
1731 | begin
|
---|
1732 | inherited Recompute;
|
---|
1733 | FContent.Recompute;
|
---|
1734 | end;
|
---|
1735 |
|
---|
1736 | procedure TSVGGradient.ScanInheritedGradients(const forceScan: boolean = false);
|
---|
1737 | var
|
---|
1738 | el: TSVGGradient;
|
---|
1739 | pos: integer;
|
---|
1740 | gradientID: string;
|
---|
1741 | begin
|
---|
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;
|
---|
1761 | end;
|
---|
1762 |
|
---|
1763 | { TSVGLinearGradient }
|
---|
1764 |
|
---|
1765 | function TSVGLinearGradient.GetX1: TFloatWithCSSUnit;
|
---|
1766 | begin
|
---|
1767 | result := GetInheritedAttribute('x1',cmNone,FloatWithCSSUnit(0,cuPercent));
|
---|
1768 | end;
|
---|
1769 |
|
---|
1770 | function TSVGLinearGradient.GetX2: TFloatWithCSSUnit;
|
---|
1771 | begin
|
---|
1772 | result := GetInheritedAttribute('x2',cmNone,FloatWithCSSUnit(100,cuPercent));
|
---|
1773 | end;
|
---|
1774 |
|
---|
1775 | function TSVGLinearGradient.GetY1: TFloatWithCSSUnit;
|
---|
1776 | begin
|
---|
1777 | result := GetInheritedAttribute('y1',cmNone,FloatWithCSSUnit(0,cuPercent));
|
---|
1778 | end;
|
---|
1779 |
|
---|
1780 | function TSVGLinearGradient.GetY2: TFloatWithCSSUnit;
|
---|
1781 | begin
|
---|
1782 | result := GetInheritedAttribute('y2',cmNone,FloatWithCSSUnit(0,cuPercent));
|
---|
1783 | end;
|
---|
1784 |
|
---|
1785 | procedure TSVGLinearGradient.SetX1(AValue: TFloatWithCSSUnit);
|
---|
1786 | begin
|
---|
1787 | AttributeWithUnit['x1']:= AValue;
|
---|
1788 | end;
|
---|
1789 |
|
---|
1790 | procedure TSVGLinearGradient.SetX2(AValue: TFloatWithCSSUnit);
|
---|
1791 | begin
|
---|
1792 | AttributeWithUnit['x2']:= AValue;
|
---|
1793 | end;
|
---|
1794 |
|
---|
1795 | procedure TSVGLinearGradient.SetY1(AValue: TFloatWithCSSUnit);
|
---|
1796 | begin
|
---|
1797 | AttributeWithUnit['y1']:= AValue;
|
---|
1798 | end;
|
---|
1799 |
|
---|
1800 | procedure TSVGLinearGradient.SetY2(AValue: TFloatWithCSSUnit);
|
---|
1801 | begin
|
---|
1802 | AttributeWithUnit['y2']:= AValue;
|
---|
1803 | end;
|
---|
1804 |
|
---|
1805 | constructor TSVGLinearGradient.Create(ADocument: TXMLDocument;
|
---|
1806 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1807 | begin
|
---|
1808 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1809 | Init(ADocument,'linearGradient',AUnits);
|
---|
1810 | end;
|
---|
1811 |
|
---|
1812 | { TSVGRadialGradient }
|
---|
1813 |
|
---|
1814 | function TSVGRadialGradient.GetCX: TFloatWithCSSUnit;
|
---|
1815 | begin
|
---|
1816 | result := GetInheritedAttribute('cx',cmHoriz,FloatWithCSSUnit(50,cuPercent));
|
---|
1817 | end;
|
---|
1818 |
|
---|
1819 | function TSVGRadialGradient.GetCY: TFloatWithCSSUnit;
|
---|
1820 | begin
|
---|
1821 | result := GetInheritedAttribute('cy',cmVertical,FloatWithCSSUnit(50,cuPercent));
|
---|
1822 | end;
|
---|
1823 |
|
---|
1824 | function TSVGRadialGradient.GetR: TFloatWithCSSUnit;
|
---|
1825 | begin
|
---|
1826 | result := GetInheritedAttribute('r',cmOrtho,FloatWithCSSUnit(50,cuPercent));
|
---|
1827 | end;
|
---|
1828 |
|
---|
1829 | function TSVGRadialGradient.GetFX: TFloatWithCSSUnit;
|
---|
1830 | begin
|
---|
1831 | result := GetInheritedAttribute('fx',cmHoriz,cx);
|
---|
1832 | end;
|
---|
1833 |
|
---|
1834 | function TSVGRadialGradient.GetFY: TFloatWithCSSUnit;
|
---|
1835 | begin
|
---|
1836 | result := GetInheritedAttribute('fy',cmVertical,cy);
|
---|
1837 | end;
|
---|
1838 |
|
---|
1839 | function TSVGRadialGradient.GetFR: TFloatWithCSSUnit;
|
---|
1840 | begin
|
---|
1841 | result := GetInheritedAttribute('fr',cmHoriz,FloatWithCSSUnit(0,cuPercent));
|
---|
1842 | end;
|
---|
1843 |
|
---|
1844 | procedure TSVGRadialGradient.SetCX(AValue: TFloatWithCSSUnit);
|
---|
1845 | begin
|
---|
1846 | HorizAttributeWithUnit['cx'] := AValue;
|
---|
1847 | end;
|
---|
1848 |
|
---|
1849 | procedure TSVGRadialGradient.SetCY(AValue: TFloatWithCSSUnit);
|
---|
1850 | begin
|
---|
1851 | VerticalAttributeWithUnit['cy'] := AValue;
|
---|
1852 | end;
|
---|
1853 |
|
---|
1854 | procedure TSVGRadialGradient.SetR(AValue: TFloatWithCSSUnit);
|
---|
1855 | begin
|
---|
1856 | OrthoAttributeWithUnit['r'] := AValue;
|
---|
1857 | end;
|
---|
1858 |
|
---|
1859 | procedure TSVGRadialGradient.SetFX(AValue: TFloatWithCSSUnit);
|
---|
1860 | begin
|
---|
1861 | HorizAttributeWithUnit['fx'] := AValue;
|
---|
1862 | end;
|
---|
1863 |
|
---|
1864 | procedure TSVGRadialGradient.SetFY(AValue: TFloatWithCSSUnit);
|
---|
1865 | begin
|
---|
1866 | VerticalAttributeWithUnit['fy'] := AValue;
|
---|
1867 | end;
|
---|
1868 |
|
---|
1869 | procedure TSVGRadialGradient.SetFR(AValue: TFloatWithCSSUnit);
|
---|
1870 | begin
|
---|
1871 | HorizAttributeWithUnit['fr'] := AValue;
|
---|
1872 | end;
|
---|
1873 |
|
---|
1874 | constructor TSVGRadialGradient.Create(ADocument: TXMLDocument;
|
---|
1875 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1876 | begin
|
---|
1877 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1878 | Init(ADocument,'radialGradient',AUnits);
|
---|
1879 | end;
|
---|
1880 |
|
---|
1881 | { TSVGStopGradient }
|
---|
1882 |
|
---|
1883 | function TSVGStopGradient.GetOffset: TFloatWithCSSUnit;
|
---|
1884 | begin
|
---|
1885 | result := AttributeWithUnit['offset'];
|
---|
1886 | end;
|
---|
1887 |
|
---|
1888 | procedure TSVGStopGradient.SetOffset(AValue: TFloatWithCSSUnit);
|
---|
1889 | begin
|
---|
1890 | AttributeWithUnit['offset'] := AValue;
|
---|
1891 | end;
|
---|
1892 |
|
---|
1893 | constructor TSVGStopGradient.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
---|
1894 | ADataLink: TSVGDataLink);
|
---|
1895 | begin
|
---|
1896 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1897 | Init(ADocument,'stop',AUnits);
|
---|
1898 | end;
|
---|
1899 |
|
---|
1900 | { TSVGDefine }
|
---|
1901 |
|
---|
1902 | constructor TSVGDefine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
---|
1903 | ADataLink: TSVGDataLink);
|
---|
1904 | begin
|
---|
1905 | inherited Create(ADocument, AUnits, ADataLink);
|
---|
1906 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
---|
1907 | end;
|
---|
1908 |
|
---|
1909 | constructor TSVGDefine.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
1910 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
---|
1911 | begin
|
---|
1912 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
---|
1913 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
---|
1914 | end;
|
---|
1915 |
|
---|
1916 | destructor TSVGDefine.Destroy;
|
---|
1917 | begin
|
---|
1918 | FreeAndNil(FContent);
|
---|
1919 | inherited Destroy;
|
---|
1920 | end;
|
---|
1921 |
|
---|
1922 | procedure TSVGDefine.Recompute;
|
---|
1923 | begin
|
---|
1924 | inherited Recompute;
|
---|
1925 | FContent.Recompute;
|
---|
1926 | end;
|
---|
1927 |
|
---|
1928 | { TSVGContent }
|
---|
1929 |
|
---|
1930 | function TSVGContent.GetElement(AIndex: integer): TSVGElement;
|
---|
1931 | begin
|
---|
1932 | result := TSVGElement(FElements.Items[AIndex]);
|
---|
1933 | end;
|
---|
1934 |
|
---|
1935 | function TSVGContent.GetElementCount: integer;
|
---|
1936 | begin
|
---|
1937 | result := FElements.Count;
|
---|
1938 | end;
|
---|
1939 |
|
---|
1940 | function TSVGContent.GetUnits: TCSSUnitConverter;
|
---|
1941 | begin
|
---|
1942 | result := FUnits;
|
---|
1943 | end;
|
---|
1944 |
|
---|
1945 | procedure TSVGContent.AppendElement(AElement: TSVGElement);
|
---|
1946 | begin
|
---|
1947 | FDomElem.AppendChild(AElement.DOMElement);
|
---|
1948 | FElements.Add(AElement);
|
---|
1949 | end;
|
---|
1950 |
|
---|
1951 | procedure TSVGContent.InsertElementBefore(AElement: TSVGElement;
|
---|
1952 | ASuccessor: TSVGElement);
|
---|
1953 | var idx: integer;
|
---|
1954 | begin
|
---|
1955 | idx := FElements.IndexOf(ASuccessor);
|
---|
1956 | if idx <> -1 then
|
---|
1957 | begin
|
---|
1958 | FElements.Insert(idx,AElement);
|
---|
1959 | FDomElem.InsertBefore(AElement.DOMElement, ASuccessor.DOMElement);
|
---|
1960 | end
|
---|
1961 | else
|
---|
1962 | begin
|
---|
1963 | FElements.Add(AElement);
|
---|
1964 | FDomElem.AppendChild(ASuccessor.DOMElement);
|
---|
1965 | end;
|
---|
1966 | end;
|
---|
1967 |
|
---|
1968 | constructor TSVGContent.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
---|
1969 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement);
|
---|
1970 | var cur: TDOMNode;
|
---|
1971 | begin
|
---|
1972 | FDoc := ADocument;
|
---|
1973 | FDomElem := AElement;
|
---|
1974 | FDataLink := ADataLink;
|
---|
1975 | FElements := TFPList.Create;
|
---|
1976 | FUnits := AUnits;
|
---|
1977 | cur := FDomElem.FirstChild;
|
---|
1978 | while cur <> nil do
|
---|
1979 | begin
|
---|
1980 | if cur is TDOMElement then
|
---|
1981 | FElements.Add(CreateSVGElementFromNode(
|
---|
1982 | ADocument,TDOMElement(cur),FUnits,ADataLink,ADataParent));
|
---|
1983 | cur := cur.NextSibling;
|
---|
1984 | end;
|
---|
1985 | end;
|
---|
1986 |
|
---|
1987 | destructor TSVGContent.Destroy;
|
---|
1988 | var i:integer;
|
---|
1989 | begin
|
---|
1990 | for i := 0 to ElementCount-1 do
|
---|
1991 | Element[i].free;
|
---|
1992 | FreeAndNil(FElements);
|
---|
1993 | inherited Destroy;
|
---|
1994 | end;
|
---|
1995 |
|
---|
1996 | procedure TSVGContent.Recompute;
|
---|
1997 | var
|
---|
1998 | i: Integer;
|
---|
1999 | begin
|
---|
2000 | for i := 0 to ElementCount-1 do
|
---|
2001 | Element[i].Recompute;
|
---|
2002 | end;
|
---|
2003 |
|
---|
2004 | procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; x, y: single; AUnit: TCSSUnit);
|
---|
2005 | var prevMatrix: TAffineMatrix;
|
---|
2006 | begin
|
---|
2007 | if (x<>0) or (y<>0) then
|
---|
2008 | begin
|
---|
2009 | prevMatrix := ACanvas2d.matrix;
|
---|
2010 | ACanvas2d.translate(x,y);
|
---|
2011 | Draw(ACanvas2d, AUnit);
|
---|
2012 | ACanvas2d.matrix := prevMatrix;
|
---|
2013 | end else
|
---|
2014 | Draw(ACanvas2d, AUnit);
|
---|
2015 | end;
|
---|
2016 |
|
---|
2017 | procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
---|
2018 | var i: integer;
|
---|
2019 | begin
|
---|
2020 | for i := 0 to ElementCount-1 do
|
---|
2021 | Element[i].Draw(ACanvas2d, AUnit);
|
---|
2022 | end;
|
---|
2023 |
|
---|
2024 | function TSVGContent.AppendLine(x1, y1, x2, y2: single; AUnit: TCSSUnit
|
---|
2025 | ): TSVGLine;
|
---|
2026 | begin
|
---|
2027 | result := TSVGLine.Create(FDoc,Units,FDataLink);
|
---|
2028 | result.x1 := FloatWithCSSUnit(x1,AUnit);
|
---|
2029 | result.y1 := FloatWithCSSUnit(y1,AUnit);
|
---|
2030 | result.x2 := FloatWithCSSUnit(x2,AUnit);
|
---|
2031 | result.y2 := FloatWithCSSUnit(y2,AUnit);
|
---|
2032 | AppendElement(result);
|
---|
2033 | end;
|
---|
2034 |
|
---|
2035 | function TSVGContent.AppendLine(p1, p2: TPointF; AUnit: TCSSUnit): TSVGLine;
|
---|
2036 | begin
|
---|
2037 | result := AppendLine(p1.x,p1.y,p2.x,p2.y,AUnit);
|
---|
2038 | end;
|
---|
2039 |
|
---|
2040 | function TSVGContent.AppendCircle(cx, cy, r: single; AUnit: TCSSUnit
|
---|
2041 | ): TSVGCircle;
|
---|
2042 | begin
|
---|
2043 | if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
|
---|
2044 | begin
|
---|
2045 | result := TSVGCircle.Create(FDoc,Units,FDataLink);
|
---|
2046 | result.cx := FloatWithCSSUnit(Units.Convert(cx,AUnit,cuCustom,Units.DpiX),cuCustom);
|
---|
2047 | result.cy := FloatWithCSSUnit(Units.Convert(cy,AUnit,cuCustom,Units.DpiY),cuCustom);
|
---|
2048 | result.r := FloatWithCSSUnit(Units.Convert(r,AUnit,cuCustom,Units.DpiX),cuCustom);
|
---|
2049 | result.transform:= Units.DpiScaleTransform;
|
---|
2050 | AppendElement(result);
|
---|
2051 | end else
|
---|
2052 | begin
|
---|
2053 | result := TSVGCircle.Create(FDoc,Units,FDataLink);
|
---|
2054 | result.cx := FloatWithCSSUnit(cx,AUnit);
|
---|
2055 | result.cy := FloatWithCSSUnit(cy,AUnit);
|
---|
2056 | result.r := FloatWithCSSUnit(r,AUnit);
|
---|
2057 | AppendElement(result);
|
---|
2058 | end;
|
---|
2059 | end;
|
---|
2060 |
|
---|
2061 | function TSVGContent.AppendCircle(c: TPointF; r: single; AUnit: TCSSUnit
|
---|
2062 | ): TSVGCircle;
|
---|
2063 | begin
|
---|
2064 | result := AppendCircle(c.x,c.y,r,AUnit);
|
---|
2065 | end;
|
---|
2066 |
|
---|
2067 | function TSVGContent.AppendEllipse(cx, cy, rx, ry: single; AUnit: TCSSUnit
|
---|
2068 | ): TSVGEllipse;
|
---|
2069 | begin
|
---|
2070 | result := TSVGEllipse.Create(FDoc,Units,FDataLink);
|
---|
2071 | result.cx := FloatWithCSSUnit(cx,AUnit);
|
---|
2072 | result.cy := FloatWithCSSUnit(cy,AUnit);
|
---|
2073 | result.rx := FloatWithCSSUnit(rx,AUnit);
|
---|
2074 | result.ry := FloatWithCSSUnit(ry,AUnit);
|
---|
2075 | AppendElement(result);
|
---|
2076 | end;
|
---|
2077 |
|
---|
2078 | function TSVGContent.AppendEllipse(c, r: TPointF; AUnit: TCSSUnit): TSVGEllipse;
|
---|
2079 | begin
|
---|
2080 | result := AppendEllipse(c.x,c.y,r.x,r.y,AUnit);
|
---|
2081 | end;
|
---|
2082 |
|
---|
2083 | function TSVGContent.AppendPath(data: string; AUnit: TCSSUnit): TSVGPath;
|
---|
2084 | var tempPath: TBGRAPath;
|
---|
2085 | begin
|
---|
2086 | if AUnit <> cuCustom then
|
---|
2087 | begin
|
---|
2088 | tempPath := TBGRAPath.Create(data);
|
---|
2089 | result := AppendPath(tempPath, AUnit);
|
---|
2090 | tempPath.Free;
|
---|
2091 | end else
|
---|
2092 | begin
|
---|
2093 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
---|
2094 | result.d := data;
|
---|
2095 | AppendElement(result);
|
---|
2096 | end;
|
---|
2097 | end;
|
---|
2098 |
|
---|
2099 | function TSVGContent.AppendPath(path: TBGRAPath; AUnit: TCSSUnit): TSVGPath;
|
---|
2100 | begin
|
---|
2101 | if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
|
---|
2102 | begin
|
---|
2103 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
---|
2104 | result.path.scale(Units.Convert(1,AUnit,cuCustom,Units.DpiX));
|
---|
2105 | path.copyTo(result.path);
|
---|
2106 | result.transform := Units.DpiScaleTransform;
|
---|
2107 | AppendElement(result);
|
---|
2108 | end else
|
---|
2109 | begin
|
---|
2110 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
---|
2111 | result.path.scale(Units.ConvertWidth(1,AUnit,cuCustom));
|
---|
2112 | path.copyTo(result.path);
|
---|
2113 | AppendElement(result);
|
---|
2114 | end;
|
---|
2115 | end;
|
---|
2116 |
|
---|
2117 | function TSVGContent.AppendPolygon(const points: array of single;
|
---|
2118 | AUnit: TCSSUnit): TSVGPolypoints;
|
---|
2119 | var
|
---|
2120 | pts: ArrayOfTPointF;
|
---|
2121 | i: integer;
|
---|
2122 | begin
|
---|
2123 | result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
|
---|
2124 | setlength(pts, length(points) div 2);
|
---|
2125 | for i := 0 to high(pts) do
|
---|
2126 | pts[i] := Units.ConvertCoord(PointF(points[i shl 1],points[(i shl 1)+1]),AUnit,cuCustom);
|
---|
2127 | result.pointsF := pts;
|
---|
2128 | AppendElement(result);
|
---|
2129 | end;
|
---|
2130 |
|
---|
2131 | function TSVGContent.AppendPolygon(const points: array of TPointF;
|
---|
2132 | AUnit: TCSSUnit): TSVGPolypoints;
|
---|
2133 | var
|
---|
2134 | pts: ArrayOfTPointF;
|
---|
2135 | i: integer;
|
---|
2136 | begin
|
---|
2137 | result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
|
---|
2138 | setlength(pts, length(points));
|
---|
2139 | for i := 0 to high(pts) do
|
---|
2140 | pts[i] := Units.ConvertCoord(points[i],AUnit,cuCustom);
|
---|
2141 | result.pointsF := pts;
|
---|
2142 | AppendElement(result);
|
---|
2143 | end;
|
---|
2144 |
|
---|
2145 | function TSVGContent.AppendRect(x, y, width, height: single; AUnit: TCSSUnit
|
---|
2146 | ): TSVGRectangle;
|
---|
2147 | begin
|
---|
2148 | result := TSVGRectangle.Create(FDoc,Units,FDataLink);
|
---|
2149 | result.x := FloatWithCSSUnit(x,AUnit);
|
---|
2150 | result.y := FloatWithCSSUnit(y,AUnit);
|
---|
2151 | result.width := FloatWithCSSUnit(width,AUnit);
|
---|
2152 | result.height := FloatWithCSSUnit(height,AUnit);
|
---|
2153 | AppendElement(result);
|
---|
2154 | end;
|
---|
2155 |
|
---|
2156 | function TSVGContent.AppendRect(origin, size: TPointF; AUnit: TCSSUnit
|
---|
2157 | ): TSVGRectangle;
|
---|
2158 | begin
|
---|
2159 | result := AppendRect(origin.x,origin.y,size.x,size.y,AUnit);
|
---|
2160 | end;
|
---|
2161 |
|
---|
2162 | function TSVGContent.AppendText(x, y: single; AText: string; AUnit: TCSSUnit
|
---|
2163 | ): TSVGText;
|
---|
2164 | begin
|
---|
2165 | result := TSVGText.Create(FDoc,Units,FDataLink);
|
---|
2166 | result.x := FloatWithCSSUnit(x,AUnit);
|
---|
2167 | result.y := FloatWithCSSUnit(y,AUnit);
|
---|
2168 | result.SimpleText:= AText;
|
---|
2169 | AppendElement(result);
|
---|
2170 | end;
|
---|
2171 |
|
---|
2172 | function TSVGContent.AppendText(origin: TPointF; AText: string; AUnit: TCSSUnit
|
---|
2173 | ): TSVGText;
|
---|
2174 | begin
|
---|
2175 | result := AppendText(origin.x,origin.y,AText,AUnit);
|
---|
2176 | end;
|
---|
2177 |
|
---|
2178 | function TSVGContent.AppendRoundRect(x, y, width, height, rx, ry: single;
|
---|
2179 | AUnit: TCSSUnit): TSVGRectangle;
|
---|
2180 | begin
|
---|
2181 | result := TSVGRectangle.Create(FDoc,Units,FDataLink);
|
---|
2182 | result.x := FloatWithCSSUnit(x,AUnit);
|
---|
2183 | result.y := FloatWithCSSUnit(y,AUnit);
|
---|
2184 | result.width := FloatWithCSSUnit(width,AUnit);
|
---|
2185 | result.height := FloatWithCSSUnit(height,AUnit);
|
---|
2186 | result.rx := FloatWithCSSUnit(rx,AUnit);
|
---|
2187 | result.ry := FloatWithCSSUnit(ry,AUnit);
|
---|
2188 | AppendElement(result);
|
---|
2189 | end;
|
---|
2190 |
|
---|
2191 | function TSVGContent.AppendRoundRect(origin, size, radius: TPointF;
|
---|
2192 | AUnit: TCSSUnit): TSVGRectangle;
|
---|
2193 | begin
|
---|
2194 | result := AppendRoundRect(origin.x,origin.y,size.x,size.y,radius.x,radius.y,AUnit);
|
---|
2195 | end;
|
---|
2196 |
|
---|
2197 | end.
|
---|
2198 |
|
---|