source: trunk/Packages/bgrabitmap/bgrasvgshapes.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 61.4 KB
Line 
1unit BGRASVGShapes;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, BGRAUnits, laz2_DOM, BGRAPath, BGRABitmapTypes,
9 BGRACanvas2D, BGRASVGType;
10
11type
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
424function GetSVGFactory(ATagName: string): TSVGFactory;
425function CreateSVGElementFromNode(ADocument: TXMLDocument;
426 AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
427
428implementation
429
430uses BGRATransform, BGRAGraphics;
431
432function GetSVGFactory(ATagName: string): TSVGFactory;
433var tag: string;
434begin
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;
463end;
464
465function CreateSVGElementFromNode(ADocument: TXMLDocument;
466 AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
467var
468 factory: TSVGFactory;
469begin
470 factory := GetSVGFactory(AElement.TagName);
471 result := factory.Create(ADocument,AElement,AUnits,ADataLink);
472
473 ADataLink.Link(result,ADataParent);
474end;
475
476{ TSVGElementWithGradient }
477
478procedure TSVGElementWithGradient.Initialize;
479begin
480 inherited Initialize;
481 ResetGradient;
482end;
483
484procedure TSVGElementWithGradient.ResetGradient;
485begin
486 FGradientElementDefined := false;
487 FGradientElement := nil;
488 FCanvasGradient := nil;
489end;
490
491function TSVGElementWithGradient.FindGradientElement: boolean;
492var
493 i: integer;
494 s: string;
495begin
496 Result:= false;
497 s:= fill;
498 if s <> '' then
499 if Pos('url(#',s) = 1 then
500 begin
501 s:= System.Copy(s,6,Length(s)-6);
502 with FDataLink do
503 for i:= GradientCount-1 downto 0 do
504 if (Gradients[i] as TSVGGradient).ID = s then
505 begin
506 FGradientElement:= TSVGGradient(Gradients[i]);
507 Result:= true;
508 Exit;
509 end;
510 end;
511end;
512
513function TSVGElementWithGradient.EvaluatePercentage(fu: TFloatWithCSSUnit): single;
514begin
515 Result:= fu.value;
516 if fu.CSSUnit <> cuPercent then
517 begin
518 if Result < 0 then
519 Result:= 0
520 else if Result > 1 then
521 Result:= 1;
522 Result:= Result * 100;
523 end;
524end;
525
526function TSVGElementWithGradient.GetGradientElement: TSVGGradient;
527begin
528 if not FGradientElementDefined then
529 begin
530 FindGradientElement;
531 FGradientElementDefined:= true;
532 if FGradientElement <> nil then
533 FGradientElement.ScanInheritedGradients;
534 end;
535 result := FGradientElement;
536end;
537
538procedure TSVGElementWithGradient.AddStopElements(canvas: IBGRACanvasGradient2D);
539
540 function AddStopElementFrom(el: TSVGElement): integer;
541 var
542 i: integer;
543 col: TBGRAPixel;
544 begin
545 result:= 0;
546 with el.DataChildList do
547 for i:= 0 to Count-1 do
548 if Items[i] is TSVGStopGradient then
549 with (Items[i] as TSVGStopGradient) do
550 begin
551 col:= StrToBGRA( AttributeOrStyleDef['stop-color','black'] );
552 col.alpha:= Round( Units.parseValue(AttributeOrStyleDef['stop-opacity','1'],1) * col.alpha );
553 canvas.addColorStop(EvaluatePercentage(offset)/100, col);
554 Inc(result);
555 end;
556 end;
557
558var
559 i: integer;
560begin
561 if not Assigned(GradientElement) then exit;
562 with GradientElement.InheritedGradients do
563 for i:= 0 to Count-1 do
564 AddStopElementFrom(Items[i]);
565end;
566
567procedure TSVGElementWithGradient.CreateCanvasLinearGradient(
568 ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
569 const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
570var p1,p2: TPointF;
571 g: TSVGLinearGradient;
572 m: TAffineMatrix;
573begin
574 g := ASVGGradient as TSVGLinearGradient;
575 if g.useObjectBoundingBox then
576 begin
577 p1.x:= EvaluatePercentage(g.x1)/100;
578 p1.y:= EvaluatePercentage(g.y1)/100;
579 p2.x:= EvaluatePercentage(g.x2)/100;
580 p2.y:= EvaluatePercentage(g.y2)/100;
581 m := ACanvas2d.matrix;
582 ACanvas2d.translate(origin.x,origin.y);
583 ACanvas2d.scale(w,h);
584 ACanvas2d.transform(g.gradientMatrix[cuCustom]);
585 FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
586 ACanvas2d.matrix := m;
587 end else
588 begin
589 p1.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
590 p1.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
591 p2.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
592 p2.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
593 m := ACanvas2d.matrix;
594 ACanvas2d.transform(g.gradientMatrix[AUnit]);
595 FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
596 ACanvas2d.matrix := m;
597 end;
598
599 AddStopElements(FCanvasGradient);
600end;
601
602procedure TSVGElementWithGradient.CreateCanvasRadialGradient(
603 ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient; const origin: TPointF;
604 const w, h: single; AUnit: TCSSUnit);
605var c,f: TPointF;
606 r,fr: single;
607 g: TSVGRadialGradient;
608 m: TAffineMatrix;
609
610 procedure CheckFocalAndCreate(c: TPointF; r: single; f: TPointF; fr: single);
611 var u: TPointF;
612 d: single;
613 begin
614 u := f-c;
615 d := VectLen(u);
616 if d >= r then
617 begin
618 u *= (r/d)*0.99999;
619 f := c+u;
620 end;
621 FCanvasGradient:= ACanvas2d.createRadialGradient(c,r,f,fr,true);
622 AddStopElements(FCanvasGradient);
623 end;
624
625begin
626 g := ASVGGradient as TSVGRadialGradient;
627 if g.useObjectBoundingBox then
628 begin
629 c.x:= EvaluatePercentage(g.cx)/100;
630 c.y:= EvaluatePercentage(g.cy)/100;
631 r:= abs(EvaluatePercentage(g.r))/100;
632 f.x:= EvaluatePercentage(g.fx)/100;
633 f.y:= EvaluatePercentage(g.fy)/100;
634 fr:= abs(EvaluatePercentage(g.fr))/100;
635
636 m := ACanvas2d.matrix;
637 ACanvas2d.translate(origin.x,origin.y);
638 ACanvas2d.scale(w,h);
639 ACanvas2d.transform(g.gradientMatrix[cuCustom]);
640 CheckFocalAndCreate(c,r,f,fr);
641 ACanvas2d.matrix := m;
642 end else
643 begin
644 c.x:= Units.ConvertWidth(g.cx,AUnit,w).value;
645 c.y:= Units.ConvertHeight(g.cy,AUnit,h).value;
646 r:= abs(Units.ConvertWidth(g.r,AUnit,w).value);
647 f.x:= Units.ConvertWidth(g.fx,AUnit,w).value;
648 f.y:= Units.ConvertHeight(g.fy,AUnit,h).value;
649 fr:= abs(Units.ConvertWidth(g.fr,AUnit,w).value);
650
651 m := ACanvas2d.matrix;
652 ACanvas2d.transform(g.gradientMatrix[AUnit]);
653 CheckFocalAndCreate(c,r,f,fr);
654 ACanvas2d.matrix := m;
655 end;
656end;
657
658procedure TSVGElementWithGradient.InitializeGradient(ACanvas2d: TBGRACanvas2D;
659 const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
660begin
661 if GradientElement <> nil then
662 begin
663 if GradientElement is TSVGLinearGradient then
664 CreateCanvasLinearGradient(ACanvas2d, GradientElement, origin, w,h, AUnit)
665 else
666 if GradientElement is TSVGRadialGradient then
667 CreateCanvasRadialGradient(ACanvas2d, GradientElement, origin, w,h, AUnit);
668 end;
669end;
670
671procedure TSVGElementWithGradient.ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit);
672begin
673 if FCanvasGradient = nil then
674 inherited ApplyFillStyle(ACanvas2D,AUnit)
675 else
676 begin
677 ACanvas2D.fillStyle(FCanvasGradient);
678 ACanvas2D.fillMode:= TFillMode(fillMode);
679 end;
680end;
681
682{ TSVGText }
683
684function TSVGText.GetFontBold: boolean;
685var valueText: string;
686begin
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');
691end;
692
693function TSVGText.GetFontFamily: string;
694begin
695 result := AttributeOrStyleDef['font-family','Arial'];
696end;
697
698function TSVGText.GetFontItalic: boolean;
699var valueText: string;
700begin
701 valueText := trim(fontStyle);
702 result := (valueText = 'oblique') or (valueText = 'italic');
703end;
704
705function TSVGText.GetFontSize: TFloatWithCSSUnit;
706begin
707 result:= VerticalAttributeOrStyleWithUnit['font-size',FloatWithCSSUnit(12,cuPoint)];
708end;
709
710function TSVGText.GetFontStyle: string;
711begin
712 result := AttributeOrStyleDef['font-style','normal'];
713end;
714
715function TSVGText.GetFontWeight: string;
716begin
717 result := AttributeOrStyleDef['font-weight','normal'];
718end;
719
720function TSVGText.GetSimpleText: string;
721begin
722 result := FDomElem.TextContent;
723end;
724
725function TSVGText.GetTextDecoration: string;
726begin
727 result := AttributeOrStyleDef['text-decoration','none'];
728end;
729
730function TSVGText.GetX: TFloatWithCSSUnit;
731begin
732 result := HorizAttributeWithUnit['x'];
733end;
734
735function TSVGText.GetY: TFloatWithCSSUnit;
736begin
737 result := VerticalAttributeWithUnit['y'];
738end;
739
740procedure TSVGText.SetFontBold(AValue: boolean);
741begin
742 if AValue then fontWeight:= 'bold' else fontWeight:= 'normal';
743end;
744
745procedure TSVGText.SetFontFamily(AValue: string);
746begin
747 Attribute['font-family'] := AValue;
748 RemoveStyle('font-family');
749end;
750
751procedure TSVGText.SetFontItalic(AValue: boolean);
752begin
753 if AValue then fontStyle:= 'italic' else fontStyle:= 'normal';
754end;
755
756procedure TSVGText.SetFontSize(AValue: TFloatWithCSSUnit);
757begin
758 VerticalAttributeWithUnit['font-size'] := AValue;
759end;
760
761procedure TSVGText.SetFontStyle(AValue: string);
762begin
763 Attribute['font-style'] := AValue;
764 RemoveStyle('font-style');
765end;
766
767procedure TSVGText.SetFontWeight(AValue: string);
768begin
769 Attribute['font-weight'] := AValue;
770 RemoveStyle('font-weight');
771end;
772
773procedure TSVGText.SetSimpleText(AValue: string);
774begin
775 FDomElem.TextContent := AValue;
776end;
777
778procedure TSVGText.SetTextDecoration(AValue: string);
779begin
780 Attribute['text-decoration'] := AValue;
781 RemoveStyle('text-decoration');
782end;
783
784procedure TSVGText.SetX(AValue: TFloatWithCSSUnit);
785begin
786 HorizAttributeWithUnit['x'] := AValue;
787end;
788
789procedure TSVGText.SetY(AValue: TFloatWithCSSUnit);
790begin
791 VerticalAttributeWithUnit['y'] := AValue;
792end;
793
794procedure TSVGText.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
795var
796 fs:TFontStyles;
797 vx,vy: single;
798begin
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;
824end;
825
826constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
827begin
828 inherited Create(ADocument, AUnits, ADataLink);
829 Init(ADocument,'text',AUnits);
830end;
831
832{ TSVGGroup }
833
834constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
835begin
836 inherited Create(ADocument, AUnits, ADataLink);
837 FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
838end;
839
840constructor TSVGGroup.Create(ADocument: TXMLDocument; AElement: TDOMElement;
841 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
842begin
843 inherited Create(ADocument, AElement, AUnits, ADataLink);
844 FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
845end;
846
847destructor TSVGGroup.Destroy;
848begin
849 FreeAndNil(FContent);
850 inherited Destroy;
851end;
852
853procedure TSVGGroup.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
854begin
855 FContent.Draw(ACanvas2d, AUnit);
856end;
857
858procedure TSVGGroup.Recompute;
859begin
860 inherited Recompute;
861 FContent.Recompute;
862end;
863
864{ TSVGStyle }
865
866constructor TSVGStyle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
867begin
868 inherited Create(ADocument, AUnits, ADataLink);
869 Init(ADocument,'style',AUnits);
870end;
871
872constructor TSVGStyle.Create(ADocument: TXMLDocument; AElement: TDOMElement;
873 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
874begin
875 inherited Create(ADocument, AElement, AUnits, ADataLink);
876 Parse(AElement.TextContent);
877end;
878
879procedure TSVGStyle.Initialize;
880begin
881 inherited Initialize;
882 Clear;
883end;
884
885destructor TSVGStyle.Destroy;
886begin
887 Clear;
888 inherited Destroy;
889end;
890
891procedure TSVGStyle.Parse(const s: String);
892
893 function IsValidAttribute(const sa: string): boolean;
894 var
895 i: integer;
896 begin
897 //(for case example "{ ; ;}")
898 for i:= 1 to Length(sa) do
899 if not (sa[i] in [' ',';']) then
900 exit(true);
901 result:= false;
902 end;
903
904const
905 EmptyRec: TSVGStyleItem = (name: ''; attribute: '');
906var
907 i,l,pg: integer;
908 st: String;
909 rec: TSVGStyleItem;
910begin
911 (*
912 Example of internal style block
913 circle {..}
914 circle.type1 {..}
915 .pic1 {..}
916 *)
917 Clear;
918 l:= 0;
919 pg:= 0;
920 st:= '';
921 rec:= EmptyRec;
922 for i:= 1 to Length(s) do
923 begin
924 if s[i] = '{' then
925 begin
926 Inc(pg);
927 if (pg = 1) and (Length(st) <> 0) then
928 begin
929 rec.name:= Trim(st);
930 st:= '';
931 end;
932 end
933 else if s[i] = '}' then
934 begin
935 Dec(pg);
936 if (pg = 0) and (Length(st) <> 0) then
937 begin
938 if IsValidAttribute(st) then
939 begin
940 rec.attribute:= Trim(st);
941 Inc(l);
942 SetLength(FStyles,l);
943 FStyles[l-1]:= rec;
944 rec:= EmptyRec;
945 end;
946 st:= '';
947 end;
948 end
949 else
950 st:= st + s[i];
951 end;
952end;
953
954function TSVGStyle.IsValidID(const sid: integer): boolean;
955begin
956 result:= (sid >= 0) and (sid < Length(FStyles));
957end;
958
959function TSVGStyle.GetStyle(const sid: integer): TSVGStyleItem;
960begin
961 if IsValidID(sid) then
962 result:= FStyles[sid]
963 else
964 raise exception.Create(rsInvalidId);
965end;
966
967procedure TSVGStyle.SetStyle(const sid: integer; sr: TSVGStyleItem);
968begin
969 if IsValidID(sid) then
970 FStyles[sid]:= sr
971 else
972 raise exception.Create(rsInvalidId);
973end;
974
975function TSVGStyle.Count: Integer;
976begin
977 result:= Length(FStyles);
978end;
979
980function TSVGStyle.Find(sr: TSVGStyleItem): integer;
981var
982 i: integer;
983begin
984 for i:= 0 to Length(FStyles)-1 do
985 with FStyles[i] do
986 if (name = sr.name) and
987 (attribute = sr.attribute) then
988 begin
989 result:= i;
990 Exit;
991 end;
992 result:= -1;
993end;
994
995function TSVGStyle.Find(const AName: string): integer;
996var
997 i: integer;
998begin
999 for i:= 0 to Length(FStyles)-1 do
1000 with FStyles[i] do
1001 if name = AName then
1002 begin
1003 result:= i;
1004 Exit;
1005 end;
1006 result:= -1;
1007end;
1008
1009function TSVGStyle.Add(sr: TSVGStyleItem): integer;
1010var
1011 l: integer;
1012begin
1013 l:= Length(FStyles);
1014 SetLength(FStyles,l+1);
1015 FStyles[l]:= sr;
1016 result:= l;
1017end;
1018
1019procedure TSVGStyle.Remove(sr: TSVGStyleItem);
1020var
1021 l,p: integer;
1022begin
1023 p:= Find(sr);
1024 l:= Length(FStyles);
1025 if p <> -1 then
1026 begin
1027 Finalize(FStyles[p]);
1028 System.Move(FStyles[p+1], FStyles[p], (l-p)*SizeOf(TSVGStyleItem));
1029 SetLength(FStyles,l-1);
1030 end;
1031end;
1032
1033procedure TSVGStyle.Clear;
1034begin
1035 SetLength(FStyles,0);
1036end;
1037
1038procedure TSVGStyle.ReParse;
1039begin
1040 Parse(FDomElem.TextContent);
1041end;
1042
1043{ TSVGRectangle }
1044
1045function TSVGRectangle.GetX: TFloatWithCSSUnit;
1046begin
1047 result := HorizAttributeWithUnit['x'];
1048end;
1049
1050function TSVGRectangle.GetY: TFloatWithCSSUnit;
1051begin
1052 result := VerticalAttributeWithUnit['y'];
1053end;
1054
1055function TSVGRectangle.GetWidth: TFloatWithCSSUnit;
1056begin
1057 result := HorizAttributeWithUnit['width'];
1058end;
1059
1060function TSVGRectangle.GetHeight: TFloatWithCSSUnit;
1061begin
1062 result := VerticalAttributeWithUnit['height'];
1063end;
1064
1065function TSVGRectangle.GetRX: TFloatWithCSSUnit;
1066begin
1067 result := HorizAttributeWithUnit['rx'];
1068end;
1069
1070function TSVGRectangle.GetRY: TFloatWithCSSUnit;
1071begin
1072 result := VerticalAttributeWithUnit['ry'];
1073end;
1074
1075procedure TSVGRectangle.SetX(AValue: TFloatWithCSSUnit);
1076begin
1077 HorizAttributeWithUnit['x'] := AValue;
1078end;
1079
1080procedure TSVGRectangle.SetY(AValue: TFloatWithCSSUnit);
1081begin
1082 VerticalAttributeWithUnit['y'] := AValue;
1083end;
1084
1085procedure TSVGRectangle.SetWidth(AValue: TFloatWithCSSUnit);
1086begin
1087 HorizAttributeWithUnit['width'] := AValue;
1088end;
1089
1090procedure TSVGRectangle.SetHeight(AValue: TFloatWithCSSUnit);
1091begin
1092 VerticalAttributeWithUnit['height'] := AValue;
1093end;
1094
1095procedure TSVGRectangle.SetRX(AValue: TFloatWithCSSUnit);
1096begin
1097 HorizAttributeWithUnit['rx'] := AValue;
1098end;
1099
1100procedure TSVGRectangle.SetRY(AValue: TFloatWithCSSUnit);
1101begin
1102 VerticalAttributeWithUnit['ry'] := AValue;
1103end;
1104
1105constructor TSVGRectangle.Create(ADocument: TXMLDocument;
1106 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1107begin
1108 inherited Create(ADocument, AUnits, ADataLink);
1109 Init(ADocument,'rect',AUnits);
1110end;
1111
1112procedure TSVGRectangle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1113var
1114 vx,vy,vw,vh: Single;
1115begin
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;
1138end;
1139
1140{ TSVGPolypoints }
1141
1142function TSVGPolypoints.GetClosed: boolean;
1143begin
1144 result := FDomElem.TagName = 'polygon';
1145end;
1146
1147function TSVGPolypoints.GetBoundingBoxF: TRectF;
1148begin
1149 if not FBoundingBoxComputed then
1150 ComputeBoundingBox(pointsF);
1151 result := FBoundingBox;
1152end;
1153
1154function TSVGPolypoints.GetPoints: string;
1155begin
1156 result := Attribute['points'];
1157end;
1158
1159function TSVGPolypoints.GetPointsF: ArrayOfTPointF;
1160var parser: TSVGParser;
1161 nbcoord,i: integer;
1162begin
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;
1179end;
1180
1181procedure TSVGPolypoints.SetPoints(AValue: string);
1182begin
1183 Attribute['points'] := AValue;
1184end;
1185
1186procedure TSVGPolypoints.SetPointsF(AValue: ArrayOfTPointF);
1187var s: string;
1188 i: integer;
1189begin
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);
1199end;
1200
1201procedure TSVGPolypoints.ComputeBoundingBox(APoints: ArrayOfTPointF);
1202var
1203 i: Integer;
1204begin
1205 if length(APoints) > 1 then
1206 begin
1207 with APoints[0] do
1208 FBoundingBox:= RectF(x,y,x,y);
1209 for i:= 1 to high(APoints) do
1210 with APoints[i] do
1211 begin
1212 if x < FBoundingBox.Left then
1213 FBoundingBox.Left:= x
1214 else if x > FBoundingBox.Right then
1215 FBoundingBox.Right:= x;
1216 if y < FBoundingBox.Top then
1217 FBoundingBox.Top:= y
1218 else if y > FBoundingBox.Bottom then
1219 FBoundingBox.Bottom:= y;
1220 end;
1221 FBoundingBoxComputed := true;
1222 end else
1223 begin
1224 FBoundingBox := RectF(0,0,0,0);
1225 FBoundingBoxComputed := true;
1226 end;
1227end;
1228
1229constructor TSVGPolypoints.Create(ADocument: TXMLDocument;
1230 AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink);
1231begin
1232 inherited Create(ADocument, AUnits, ADataLink);
1233 if AClosed then
1234 Init(ADocument, 'polygon', AUnits)
1235 else
1236 Init(ADocument, 'polyline', AUnits);
1237end;
1238
1239destructor TSVGPolypoints.Destroy;
1240begin
1241 inherited Destroy;
1242end;
1243
1244procedure TSVGPolypoints.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1245var
1246 prevMatrix: TAffineMatrix;
1247 pts: ArrayOfTPointF;
1248begin
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;
1279end;
1280
1281{ TSVGPath }
1282
1283function TSVGPath.GetPathLength: TFloatWithCSSUnit;
1284begin
1285 result := OrthoAttributeWithUnit['pathLength'];
1286end;
1287
1288function TSVGPath.GetPath: TBGRAPath;
1289begin
1290 if FPath = nil then
1291 FPath := TBGRAPath.Create(Attribute['d']);
1292 result := FPath;
1293end;
1294
1295function TSVGPath.GetBoundingBoxF: TRectF;
1296begin
1297 if not FBoundingBoxComputed then
1298 begin
1299 FBoundingBox := path.GetBounds;
1300 FBoundingBoxComputed := true;
1301 end;
1302 result := FBoundingBox;
1303end;
1304
1305function TSVGPath.GetData: string;
1306begin
1307 if FPath = nil then
1308 result := Attribute['d']
1309 else
1310 result := FPath.SvgString;
1311end;
1312
1313procedure TSVGPath.SetPathLength(AValue: TFloatWithCSSUnit);
1314begin
1315 OrthoAttributeWithUnit['pathLength'] := AValue;
1316end;
1317
1318procedure TSVGPath.SetData(AValue: string);
1319begin
1320 if FPath = nil then
1321 Attribute['d'] := AValue
1322 else
1323 FPath.SvgString := AValue;
1324 FBoundingBoxComputed := false;
1325end;
1326
1327function TSVGPath.GetDOMElement: TDOMElement;
1328begin
1329 if FPath <> nil then Attribute['d'] := FPath.SvgString;
1330 Result:=inherited GetDOMElement;
1331end;
1332
1333constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1334begin
1335 inherited Create(ADocument, AUnits, ADataLink);
1336 Init(ADocument,'path',AUnits);
1337 FPath := nil;
1338 FBoundingBoxComputed := false;
1339 FBoundingBox := rectF(0,0,0,0);
1340end;
1341
1342constructor TSVGPath.Create(ADocument: TXMLDocument; AElement: TDOMElement;
1343 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1344begin
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);
1350end;
1351
1352destructor TSVGPath.Destroy;
1353begin
1354 FreeAndNil(FPath);
1355 inherited Destroy;
1356end;
1357
1358procedure TSVGPath.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1359var
1360 prevMatrix: TAffineMatrix;
1361begin
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;
1388end;
1389
1390{ TSVGEllipse }
1391
1392function TSVGEllipse.GetCX: TFloatWithCSSUnit;
1393begin
1394 result := HorizAttributeWithUnit['cx'];
1395end;
1396
1397function TSVGEllipse.GetCY: TFloatWithCSSUnit;
1398begin
1399 result := VerticalAttributeWithUnit['cy'];
1400end;
1401
1402function TSVGEllipse.GetRX: TFloatWithCSSUnit;
1403begin
1404 result := HorizAttributeWithUnit['rx'];
1405end;
1406
1407function TSVGEllipse.GetRY: TFloatWithCSSUnit;
1408begin
1409 result := VerticalAttributeWithUnit['ry'];
1410end;
1411
1412procedure TSVGEllipse.SetCX(AValue: TFloatWithCSSUnit);
1413begin
1414 HorizAttributeWithUnit['cx'] := AValue;
1415end;
1416
1417procedure TSVGEllipse.SetCY(AValue: TFloatWithCSSUnit);
1418begin
1419 VerticalAttributeWithUnit['cy'] := AValue;
1420end;
1421
1422procedure TSVGEllipse.SetRX(AValue: TFloatWithCSSUnit);
1423begin
1424 HorizAttributeWithUnit['rx'] := AValue;
1425end;
1426
1427procedure TSVGEllipse.SetRY(AValue: TFloatWithCSSUnit);
1428begin
1429 VerticalAttributeWithUnit['ry'] := AValue;
1430end;
1431
1432constructor TSVGEllipse.Create(ADocument: TXMLDocument;
1433 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1434begin
1435 inherited Create(ADocument, AUnits, ADataLink);
1436 Init(ADocument,'ellipse',AUnits);
1437end;
1438
1439procedure TSVGEllipse.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1440var
1441 vcx,vcy,vrx,vry: Single;
1442begin
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;
1464end;
1465
1466{ TSVGCircle }
1467
1468function TSVGCircle.GetCX: TFloatWithCSSUnit;
1469begin
1470 result := HorizAttributeWithUnit['cx'];
1471end;
1472
1473function TSVGCircle.GetCY: TFloatWithCSSUnit;
1474begin
1475 result := VerticalAttributeWithUnit['cy'];
1476end;
1477
1478function TSVGCircle.GetR: TFloatWithCSSUnit;
1479begin
1480 result := OrthoAttributeWithUnit['r'];
1481end;
1482
1483procedure TSVGCircle.SetCX(AValue: TFloatWithCSSUnit);
1484begin
1485 HorizAttributeWithUnit['cx'] := AValue;
1486end;
1487
1488procedure TSVGCircle.SetCY(AValue: TFloatWithCSSUnit);
1489begin
1490 VerticalAttributeWithUnit['cy'] := AValue;
1491end;
1492
1493procedure TSVGCircle.SetR(AValue: TFloatWithCSSUnit);
1494begin
1495 OrthoAttributeWithUnit['r'] := AValue;
1496end;
1497
1498constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1499begin
1500 inherited Create(ADocument, AUnits, ADataLink);
1501 Init(ADocument,'circle',AUnits);
1502end;
1503
1504procedure TSVGCircle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1505var
1506 vcx,vcy,vr: Single;
1507begin
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;
1528end;
1529
1530{ TSVGLine }
1531
1532function TSVGLine.GetX1: TFloatWithCSSUnit;
1533begin
1534 result := HorizAttributeWithUnit['x1'];
1535end;
1536
1537function TSVGLine.GetX2: TFloatWithCSSUnit;
1538begin
1539 result := HorizAttributeWithUnit['x2'];
1540end;
1541
1542function TSVGLine.GetY1: TFloatWithCSSUnit;
1543begin
1544 result := VerticalAttributeWithUnit['y1'];
1545end;
1546
1547function TSVGLine.GetY2: TFloatWithCSSUnit;
1548begin
1549 result := VerticalAttributeWithUnit['y2'];
1550end;
1551
1552procedure TSVGLine.SetX1(AValue: TFloatWithCSSUnit);
1553begin
1554 HorizAttributeWithUnit['x1'] := AValue;
1555end;
1556
1557procedure TSVGLine.SetX2(AValue: TFloatWithCSSUnit);
1558begin
1559 HorizAttributeWithUnit['x2'] := AValue;
1560end;
1561
1562procedure TSVGLine.SetY1(AValue: TFloatWithCSSUnit);
1563begin
1564 VerticalAttributeWithUnit['y1'] := AValue;
1565end;
1566
1567procedure TSVGLine.SetY2(AValue: TFloatWithCSSUnit);
1568begin
1569 VerticalAttributeWithUnit['y2'] := AValue;
1570end;
1571
1572constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1573begin
1574 inherited Create(ADocument, AUnits, ADataLink);
1575 Init(ADocument,'line',AUnits);
1576end;
1577
1578procedure TSVGLine.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
1579begin
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;
1588end;
1589
1590{ TSVGGradient } //##
1591
1592function TSVGGradient.GetHRef: string;
1593begin
1594 result := Attribute['xlink:href'];
1595 if result = '' then
1596 result := Attribute['href'];//(Note: specific for svg 2)
1597end;
1598
1599function TSVGGradient.GetUseObjectBoundingBox: boolean;
1600begin
1601 result := (gradientUnits = 'objectBoundingBox');
1602end;
1603
1604procedure TSVGGradient.SetGradientTransform(AValue: string);
1605begin
1606 Attribute['gradientTransform'] := AValue;
1607end;
1608
1609function TSVGGradient.GetGradientUnits: string;
1610begin
1611 result := AttributeDef['gradientUnits','objectBoundingBox'];
1612end;
1613
1614function TSVGGradient.GetGradientTransform: string;
1615begin
1616 result := Attribute['gradientTransform'];
1617end;
1618
1619function TSVGGradient.GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
1620var parser: TSVGParser;
1621 s: string;
1622begin
1623 s := gradientTransform;
1624 if s = '' then
1625 begin
1626 result := AffineMatrixIdentity;
1627 exit;
1628 end;
1629 parser := TSVGParser.Create(s);
1630 result := parser.ParseTransform;
1631 parser.Free;
1632 result[1,3] := Units.ConvertWidth(result[1,3],cuCustom,AUnit);
1633 result[2,3] := Units.ConvertHeight(result[2,3],cuCustom,AUnit);
1634end;
1635
1636procedure TSVGGradient.SetGradientUnits(AValue: string);
1637begin
1638 Attribute['gradientUnits'] := AValue;
1639end;
1640
1641procedure TSVGGradient.SetHRef(AValue: string);
1642begin
1643 Attribute['xlink:href'] := AValue;
1644end;
1645
1646constructor TSVGGradient.Create(ADocument: TXMLDocument;
1647 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1648begin
1649 inherited Create(ADocument, AUnits, ADataLink);
1650 FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
1651end;
1652
1653function TSVGGradient.HRefToGradientID(const AValue: string): string;
1654var
1655 l: integer;
1656begin
1657 //(example input: "#gradient1")
1658 l:= Length(AValue);
1659 if l < 2 then
1660 result:= ''
1661 else
1662 result:= System.Copy(AValue,2,l-1);
1663end;
1664
1665function TSVGGradient.FindGradientRef(const AGradientID: string): integer;
1666var
1667 i: integer;
1668begin
1669 with FDataLink do
1670 for i:= 0 to GradientCount-1 do
1671 if (Gradients[i] as TSVGGradient).ID = AGradientID then
1672 begin
1673 result:= i;
1674 exit;
1675 end;
1676 result:= -1;
1677end;
1678
1679procedure TSVGGradient.Initialize;
1680begin
1681 inherited;
1682 InheritedGradients:= TSVGElementList.Create;
1683end;
1684
1685function TSVGGradient.GetInheritedAttribute(AValue: string;
1686 AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
1687var
1688 i: integer;
1689 el: TSVGGradient;
1690 invalidDef: TFloatWithCSSUnit;
1691begin
1692 invalidDef:= FloatWithCSSUnit(EmptySingle,cuPercent);
1693 //find valid inherited attribute (start from "self": item[0])
1694 for i:= 0 to InheritedGradients.Count-1 do
1695 begin
1696 el:= TSVGGradient( InheritedGradients[i] );
1697 with el do
1698 begin
1699 if AConvMethod = cmHoriz then
1700 result:= HorizAttributeWithUnitDef[AValue,invalidDef]
1701 else if AConvMethod = cmVertical then
1702 result:= VerticalAttributeWithUnitDef[AValue,invalidDef]
1703 else if AConvMethod = cmOrtho then
1704 result:= OrthoAttributeWithUnitDef[AValue,invalidDef]
1705 else
1706 result:= AttributeWithUnitDef[AValue,invalidDef];
1707
1708 if (result.value <> invalidDef.value) or
1709 (result.CSSUnit <> invalidDef.CSSUnit) then
1710 exit;
1711 end;
1712 end;
1713 result:= ADefault;
1714end;
1715
1716constructor TSVGGradient.Create(ADocument: TXMLDocument; AElement: TDOMElement;
1717 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1718begin
1719 inherited Create(ADocument, AElement, AUnits, ADataLink);
1720 FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
1721end;
1722
1723destructor TSVGGradient.Destroy;
1724begin
1725 FreeAndNil(FContent);
1726 FreeAndNil(InheritedGradients);
1727 inherited Destroy;
1728end;
1729
1730procedure TSVGGradient.Recompute;
1731begin
1732 inherited Recompute;
1733 FContent.Recompute;
1734end;
1735
1736procedure TSVGGradient.ScanInheritedGradients(const forceScan: boolean = false);
1737var
1738 el: TSVGGradient;
1739 pos: integer;
1740 gradientID: string;
1741begin
1742 //(if list empty = not scan)
1743 if (InheritedGradients.Count <> 0) and (not forceScan) then
1744 exit;
1745
1746 InheritedGradients.Clear;
1747 InheritedGradients.Add(Self);//(important)
1748 el:= Self;
1749 while el.hRef <> '' do
1750 begin
1751 gradientID:= HRefToGradientID(el.hRef);
1752 pos:= FindGradientRef(gradientID);
1753 if pos = -1 then
1754 exit
1755 else
1756 begin
1757 el:= TSVGGradient(FDataLink.Gradients[pos]);
1758 InheritedGradients.Add(el);
1759 end;
1760 end;
1761end;
1762
1763{ TSVGLinearGradient }
1764
1765function TSVGLinearGradient.GetX1: TFloatWithCSSUnit;
1766begin
1767 result := GetInheritedAttribute('x1',cmNone,FloatWithCSSUnit(0,cuPercent));
1768end;
1769
1770function TSVGLinearGradient.GetX2: TFloatWithCSSUnit;
1771begin
1772 result := GetInheritedAttribute('x2',cmNone,FloatWithCSSUnit(100,cuPercent));
1773end;
1774
1775function TSVGLinearGradient.GetY1: TFloatWithCSSUnit;
1776begin
1777 result := GetInheritedAttribute('y1',cmNone,FloatWithCSSUnit(0,cuPercent));
1778end;
1779
1780function TSVGLinearGradient.GetY2: TFloatWithCSSUnit;
1781begin
1782 result := GetInheritedAttribute('y2',cmNone,FloatWithCSSUnit(0,cuPercent));
1783end;
1784
1785procedure TSVGLinearGradient.SetX1(AValue: TFloatWithCSSUnit);
1786begin
1787 AttributeWithUnit['x1']:= AValue;
1788end;
1789
1790procedure TSVGLinearGradient.SetX2(AValue: TFloatWithCSSUnit);
1791begin
1792 AttributeWithUnit['x2']:= AValue;
1793end;
1794
1795procedure TSVGLinearGradient.SetY1(AValue: TFloatWithCSSUnit);
1796begin
1797 AttributeWithUnit['y1']:= AValue;
1798end;
1799
1800procedure TSVGLinearGradient.SetY2(AValue: TFloatWithCSSUnit);
1801begin
1802 AttributeWithUnit['y2']:= AValue;
1803end;
1804
1805constructor TSVGLinearGradient.Create(ADocument: TXMLDocument;
1806 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1807begin
1808 inherited Create(ADocument, AUnits, ADataLink);
1809 Init(ADocument,'linearGradient',AUnits);
1810end;
1811
1812{ TSVGRadialGradient }
1813
1814function TSVGRadialGradient.GetCX: TFloatWithCSSUnit;
1815begin
1816 result := GetInheritedAttribute('cx',cmHoriz,FloatWithCSSUnit(50,cuPercent));
1817end;
1818
1819function TSVGRadialGradient.GetCY: TFloatWithCSSUnit;
1820begin
1821 result := GetInheritedAttribute('cy',cmVertical,FloatWithCSSUnit(50,cuPercent));
1822end;
1823
1824function TSVGRadialGradient.GetR: TFloatWithCSSUnit;
1825begin
1826 result := GetInheritedAttribute('r',cmOrtho,FloatWithCSSUnit(50,cuPercent));
1827end;
1828
1829function TSVGRadialGradient.GetFX: TFloatWithCSSUnit;
1830begin
1831 result := GetInheritedAttribute('fx',cmHoriz,cx);
1832end;
1833
1834function TSVGRadialGradient.GetFY: TFloatWithCSSUnit;
1835begin
1836 result := GetInheritedAttribute('fy',cmVertical,cy);
1837end;
1838
1839function TSVGRadialGradient.GetFR: TFloatWithCSSUnit;
1840begin
1841 result := GetInheritedAttribute('fr',cmHoriz,FloatWithCSSUnit(0,cuPercent));
1842end;
1843
1844procedure TSVGRadialGradient.SetCX(AValue: TFloatWithCSSUnit);
1845begin
1846 HorizAttributeWithUnit['cx'] := AValue;
1847end;
1848
1849procedure TSVGRadialGradient.SetCY(AValue: TFloatWithCSSUnit);
1850begin
1851 VerticalAttributeWithUnit['cy'] := AValue;
1852end;
1853
1854procedure TSVGRadialGradient.SetR(AValue: TFloatWithCSSUnit);
1855begin
1856 OrthoAttributeWithUnit['r'] := AValue;
1857end;
1858
1859procedure TSVGRadialGradient.SetFX(AValue: TFloatWithCSSUnit);
1860begin
1861 HorizAttributeWithUnit['fx'] := AValue;
1862end;
1863
1864procedure TSVGRadialGradient.SetFY(AValue: TFloatWithCSSUnit);
1865begin
1866 VerticalAttributeWithUnit['fy'] := AValue;
1867end;
1868
1869procedure TSVGRadialGradient.SetFR(AValue: TFloatWithCSSUnit);
1870begin
1871 HorizAttributeWithUnit['fr'] := AValue;
1872end;
1873
1874constructor TSVGRadialGradient.Create(ADocument: TXMLDocument;
1875 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1876begin
1877 inherited Create(ADocument, AUnits, ADataLink);
1878 Init(ADocument,'radialGradient',AUnits);
1879end;
1880
1881{ TSVGStopGradient }
1882
1883function TSVGStopGradient.GetOffset: TFloatWithCSSUnit;
1884begin
1885 result := AttributeWithUnit['offset'];
1886end;
1887
1888procedure TSVGStopGradient.SetOffset(AValue: TFloatWithCSSUnit);
1889begin
1890 AttributeWithUnit['offset'] := AValue;
1891end;
1892
1893constructor TSVGStopGradient.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
1894 ADataLink: TSVGDataLink);
1895begin
1896 inherited Create(ADocument, AUnits, ADataLink);
1897 Init(ADocument,'stop',AUnits);
1898end;
1899
1900{ TSVGDefine }
1901
1902constructor TSVGDefine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
1903 ADataLink: TSVGDataLink);
1904begin
1905 inherited Create(ADocument, AUnits, ADataLink);
1906 FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
1907end;
1908
1909constructor TSVGDefine.Create(ADocument: TXMLDocument; AElement: TDOMElement;
1910 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
1911begin
1912 inherited Create(ADocument, AElement, AUnits, ADataLink);
1913 FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
1914end;
1915
1916destructor TSVGDefine.Destroy;
1917begin
1918 FreeAndNil(FContent);
1919 inherited Destroy;
1920end;
1921
1922procedure TSVGDefine.Recompute;
1923begin
1924 inherited Recompute;
1925 FContent.Recompute;
1926end;
1927
1928{ TSVGContent }
1929
1930function TSVGContent.GetElement(AIndex: integer): TSVGElement;
1931begin
1932 result := TSVGElement(FElements.Items[AIndex]);
1933end;
1934
1935function TSVGContent.GetElementCount: integer;
1936begin
1937 result := FElements.Count;
1938end;
1939
1940function TSVGContent.GetUnits: TCSSUnitConverter;
1941begin
1942 result := FUnits;
1943end;
1944
1945procedure TSVGContent.AppendElement(AElement: TSVGElement);
1946begin
1947 FDomElem.AppendChild(AElement.DOMElement);
1948 FElements.Add(AElement);
1949end;
1950
1951procedure TSVGContent.InsertElementBefore(AElement: TSVGElement;
1952 ASuccessor: TSVGElement);
1953var idx: integer;
1954begin
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;
1966end;
1967
1968constructor TSVGContent.Create(ADocument: TXMLDocument; AElement: TDOMElement;
1969 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement);
1970var cur: TDOMNode;
1971begin
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;
1985end;
1986
1987destructor TSVGContent.Destroy;
1988var i:integer;
1989begin
1990 for i := 0 to ElementCount-1 do
1991 Element[i].free;
1992 FreeAndNil(FElements);
1993 inherited Destroy;
1994end;
1995
1996procedure TSVGContent.Recompute;
1997var
1998 i: Integer;
1999begin
2000 for i := 0 to ElementCount-1 do
2001 Element[i].Recompute;
2002end;
2003
2004procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; x, y: single; AUnit: TCSSUnit);
2005var prevMatrix: TAffineMatrix;
2006begin
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);
2015end;
2016
2017procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
2018var i: integer;
2019begin
2020 for i := 0 to ElementCount-1 do
2021 Element[i].Draw(ACanvas2d, AUnit);
2022end;
2023
2024function TSVGContent.AppendLine(x1, y1, x2, y2: single; AUnit: TCSSUnit
2025 ): TSVGLine;
2026begin
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);
2033end;
2034
2035function TSVGContent.AppendLine(p1, p2: TPointF; AUnit: TCSSUnit): TSVGLine;
2036begin
2037 result := AppendLine(p1.x,p1.y,p2.x,p2.y,AUnit);
2038end;
2039
2040function TSVGContent.AppendCircle(cx, cy, r: single; AUnit: TCSSUnit
2041 ): TSVGCircle;
2042begin
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;
2059end;
2060
2061function TSVGContent.AppendCircle(c: TPointF; r: single; AUnit: TCSSUnit
2062 ): TSVGCircle;
2063begin
2064 result := AppendCircle(c.x,c.y,r,AUnit);
2065end;
2066
2067function TSVGContent.AppendEllipse(cx, cy, rx, ry: single; AUnit: TCSSUnit
2068 ): TSVGEllipse;
2069begin
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);
2076end;
2077
2078function TSVGContent.AppendEllipse(c, r: TPointF; AUnit: TCSSUnit): TSVGEllipse;
2079begin
2080 result := AppendEllipse(c.x,c.y,r.x,r.y,AUnit);
2081end;
2082
2083function TSVGContent.AppendPath(data: string; AUnit: TCSSUnit): TSVGPath;
2084var tempPath: TBGRAPath;
2085begin
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;
2097end;
2098
2099function TSVGContent.AppendPath(path: TBGRAPath; AUnit: TCSSUnit): TSVGPath;
2100begin
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;
2115end;
2116
2117function TSVGContent.AppendPolygon(const points: array of single;
2118 AUnit: TCSSUnit): TSVGPolypoints;
2119var
2120 pts: ArrayOfTPointF;
2121 i: integer;
2122begin
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);
2129end;
2130
2131function TSVGContent.AppendPolygon(const points: array of TPointF;
2132 AUnit: TCSSUnit): TSVGPolypoints;
2133var
2134 pts: ArrayOfTPointF;
2135 i: integer;
2136begin
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);
2143end;
2144
2145function TSVGContent.AppendRect(x, y, width, height: single; AUnit: TCSSUnit
2146 ): TSVGRectangle;
2147begin
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);
2154end;
2155
2156function TSVGContent.AppendRect(origin, size: TPointF; AUnit: TCSSUnit
2157 ): TSVGRectangle;
2158begin
2159 result := AppendRect(origin.x,origin.y,size.x,size.y,AUnit);
2160end;
2161
2162function TSVGContent.AppendText(x, y: single; AText: string; AUnit: TCSSUnit
2163 ): TSVGText;
2164begin
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);
2170end;
2171
2172function TSVGContent.AppendText(origin: TPointF; AText: string; AUnit: TCSSUnit
2173 ): TSVGText;
2174begin
2175 result := AppendText(origin.x,origin.y,AText,AUnit);
2176end;
2177
2178function TSVGContent.AppendRoundRect(x, y, width, height, rx, ry: single;
2179 AUnit: TCSSUnit): TSVGRectangle;
2180begin
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);
2189end;
2190
2191function TSVGContent.AppendRoundRect(origin, size, radius: TPointF;
2192 AUnit: TCSSUnit): TSVGRectangle;
2193begin
2194 result := AppendRoundRect(origin.x,origin.y,size.x,size.y,radius.x,radius.y,AUnit);
2195end;
2196
2197end.
2198
Note: See TracBrowser for help on using the repository browser.