Changeset 521 for GraphicTest/Packages/bgrabitmap/bgrasvgshapes.pas
- Timestamp:
- Apr 17, 2019, 12:58:41 AM (5 years ago)
- Location:
- GraphicTest
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest
- Property svn:ignore
-
old new 8 8 GraphicTest.lps 9 9 GraphicTest.dbg 10 heaptrclog.trc
-
- Property svn:ignore
-
GraphicTest/Packages/bgrabitmap/bgrasvgshapes.pas
r494 r521 10 10 11 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 12 39 { TSVGLine } 13 40 … … 25 52 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 26 53 public 27 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;54 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 28 55 property x1: TFloatWithCSSUnit read GetX1 write SetX1; 29 56 property y1: TFloatWithCSSUnit read GetY1 write SetY1; … … 34 61 { TSVGRectangle } 35 62 36 TSVGRectangle = class(TSVGElement )63 TSVGRectangle = class(TSVGElementWithGradient) 37 64 private 38 65 function GetX: TFloatWithCSSUnit; … … 51 78 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 52 79 public 53 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;80 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 54 81 property x: TFloatWithCSSUnit read GetX write SetX; 55 82 property y: TFloatWithCSSUnit read GetY write SetY; … … 62 89 { TSVGCircle } 63 90 64 TSVGCircle = class(TSVGElement )91 TSVGCircle = class(TSVGElementWithGradient) 65 92 private 66 93 function GetCX: TFloatWithCSSUnit; … … 73 100 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 74 101 public 75 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;102 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 76 103 property cx: TFloatWithCSSUnit read GetCX write SetCX; 77 104 property cy: TFloatWithCSSUnit read GetCY write SetCY; … … 81 108 { TSVGEllipse } 82 109 83 TSVGEllipse = class(TSVGElement )110 TSVGEllipse = class(TSVGElementWithGradient) 84 111 private 85 112 function GetCX: TFloatWithCSSUnit; … … 94 121 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 95 122 public 96 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;123 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 97 124 property cx: TFloatWithCSSUnit read GetCX write SetCX; 98 125 property cy: TFloatWithCSSUnit read GetCY write SetCY; … … 103 130 { TSVGPath } 104 131 105 TSVGPath = class(TSVGElement )132 TSVGPath = class(TSVGElementWithGradient) 106 133 private 107 134 FPath: TBGRAPath; 135 FBoundingBox: TRectF; 136 FBoundingBoxComputed: boolean; 137 function GetBoundingBoxF: TRectF; 108 138 function GetPath: TBGRAPath; 109 139 function GetPathLength: TFloatWithCSSUnit; … … 115 145 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 116 146 public 117 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;118 constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter ); override;147 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 148 constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 119 149 destructor Destroy; override; 120 150 property d: string read GetData write SetData; 121 151 property path: TBGRAPath read GetPath; 122 152 property pathLength: TFloatWithCSSUnit read GetPathLength write SetPathLength; 153 property boundingBoxF: TRectF read GetBoundingBoxF; 123 154 end; 124 155 125 156 { TSVGPolypoints } 126 157 127 TSVGPolypoints = class(TSVGElement )158 TSVGPolypoints = class(TSVGElementWithGradient) 128 159 private 160 FBoundingBox: TRectF; 161 FBoundingBoxComputed: boolean; 162 function GetBoundingBoxF: TRectF; 129 163 function GetClosed: boolean; 130 164 function GetPoints: string; … … 132 166 procedure SetPoints(AValue: string); 133 167 procedure SetPointsF(AValue: ArrayOfTPointF); 168 procedure ComputeBoundingBox(APoints: ArrayOfTPointF); 134 169 protected 135 170 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 136 171 public 137 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean ); overload;172 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink); overload; 138 173 destructor Destroy; override; 139 174 property points: string read GetPoints write SetPoints; 140 175 property pointsF: ArrayOfTPointF read GetPointsF write SetPointsF; 141 176 property closed: boolean read GetClosed; 177 property boundingBoxF: TRectF read GetBoundingBoxF; 142 178 end; 143 179 144 180 { TSVGText } 145 181 146 TSVGText = class(TSVGElement )182 TSVGText = class(TSVGElementWithGradient) 147 183 private 148 184 function GetFontBold: boolean; … … 169 205 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 170 206 public 171 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;207 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 172 208 property x: TFloatWithCSSUnit read GetX write SetX; 173 209 property y: TFloatWithCSSUnit read GetY write SetY; … … 183 219 184 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; 185 334 186 335 { TSVGGroup } … … 191 340 procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override; 192 341 public 193 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter ); override;342 constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 194 343 constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; 195 AUnits: TCSSUnitConverter ); override;344 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override; 196 345 destructor Destroy; override; 346 procedure Recompute; override; 197 347 property Content: TSVGContent read FContent; 198 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; 199 381 200 382 { TSVGContent } … … 202 384 TSVGContent = class 203 385 protected 386 FDataLink: TSVGDataLink; 204 387 FDomElem: TDOMElement; 205 388 FDoc: TXMLDocument; 206 FElements: T List;389 FElements: TFPList; 207 390 FUnits: TCSSUnitConverter; 208 391 procedure AppendElement(AElement: TSVGElement); … … 212 395 function GetUnits: TCSSUnitConverter; 213 396 public 214 constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter); 397 constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; 398 ADataLink: TSVGDataLink; ADataParent: TSVGElement); 215 399 destructor Destroy; override; 400 procedure Recompute; 216 401 procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; AUnit: TCSSUnit); overload; 217 402 procedure Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); overload; … … 239 424 function GetSVGFactory(ATagName: string): TSVGFactory; 240 425 function CreateSVGElementFromNode(ADocument: TXMLDocument; 241 AElement: TDOMElement; AUnits: TCSSUnitConverter ): TSVGElement;426 AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement; 242 427 243 428 implementation … … 263 448 if tag='text' then 264 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 265 458 if tag='g' then 266 459 result := TSVGGroup else 460 if tag='style' then 461 result := TSVGStyle else 267 462 result := TSVGElement; 268 463 end; 269 464 270 465 function CreateSVGElementFromNode(ADocument: TXMLDocument; 271 AElement: TDOMElement; AUnits: TCSSUnitConverter ): TSVGElement;466 AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement; 272 467 var 273 468 factory: TSVGFactory; 274 469 begin 275 470 factory := GetSVGFactory(AElement.TagName); 276 result := factory.Create(ADocument,AElement,AUnits); 277 end; 471 result := factory.Create(ADocument,AElement,AUnits,ADataLink); 472 473 ADataLink.Link(result,ADataParent); 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; 278 681 279 682 { TSVGText } … … 290 693 function TSVGText.GetFontFamily: string; 291 694 begin 292 result := AttributeOrStyle['font-family']; 293 if result = '' then result := 'Arial'; 695 result := AttributeOrStyleDef['font-family','Arial']; 294 696 end; 295 697 … … 303 705 function TSVGText.GetFontSize: TFloatWithCSSUnit; 304 706 begin 305 if AttributeOrStyle['font-size']='' then 306 result := FloatWithCSSUnit(12,cuPoint) 307 else 308 result := VerticalAttributeOrStyleWithUnit['font-size']; 707 result:= VerticalAttributeOrStyleWithUnit['font-size',FloatWithCSSUnit(12,cuPoint)]; 309 708 end; 310 709 311 710 function TSVGText.GetFontStyle: string; 312 711 begin 313 result := AttributeOrStyle['font-style']; 314 if result = '' then result := 'normal'; 712 result := AttributeOrStyleDef['font-style','normal']; 315 713 end; 316 714 317 715 function TSVGText.GetFontWeight: string; 318 716 begin 319 result := AttributeOrStyle['font-weight']; 320 if result = '' then result := 'normal'; 717 result := AttributeOrStyleDef['font-weight','normal']; 321 718 end; 322 719 … … 328 725 function TSVGText.GetTextDecoration: string; 329 726 begin 330 result := AttributeOrStyle['text-decoration']; 331 if result='' then result := 'none'; 727 result := AttributeOrStyleDef['text-decoration','none']; 332 728 end; 333 729 … … 397 793 398 794 procedure TSVGText.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); 399 var fs:TFontStyles; 795 var 796 fs:TFontStyles; 797 vx,vy: single; 400 798 begin 401 799 ACanvas2d.beginPath; 402 ACanvas2d.fontEmHeight := Units.Convert Width(fontSize,AUnit).value;800 ACanvas2d.fontEmHeight := Units.ConvertHeight(fontSize,AUnit).value; 403 801 ACanvas2d.fontName := fontFamily; 404 802 fs := []; … … 406 804 if fontItalic then fs += [fsItalic]; 407 805 ACanvas2d.fontStyle := fs; 408 ACanvas2d.text(SimpleText,Units.ConvertWidth(x,AUnit).value,Units.ConvertWidth(y,AUnit).value); 806 vx:= Units.ConvertWidth(x,AUnit).value; 807 vy:= Units.ConvertHeight(y,AUnit).value; 808 ACanvas2d.text(SimpleText,vx,vy); 809 810 if Assigned(GradientElement) then 811 with ACanvas2d.measureText(SimpleText) do 812 InitializeGradient(ACanvas2d, PointF(vx,vy),width,height,AUnit); 813 409 814 if not isFillNone then 410 815 begin 411 A Canvas2d.fillStyle(fillColor);816 ApplyFillStyle(ACanvas2D,AUnit); 412 817 ACanvas2d.fill; 413 818 end; … … 419 824 end; 420 825 421 constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); 422 begin 826 constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 827 begin 828 inherited Create(ADocument, AUnits, ADataLink); 423 829 Init(ADocument,'text',AUnits); 424 830 end; … … 426 832 { TSVGGroup } 427 833 428 constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter );429 begin 430 inherited Create(ADocument, AUnits );431 FContent := TSVGContent.Create(ADocument,FDomElem,AUnits );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); 432 838 end; 433 839 434 840 constructor TSVGGroup.Create(ADocument: TXMLDocument; AElement: TDOMElement; 435 AUnits: TCSSUnitConverter );436 begin 437 inherited Create(ADocument, AElement, AUnits );438 FContent := TSVGContent.Create(ADocument,AElement,AUnits );841 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 842 begin 843 inherited Create(ADocument, AElement, AUnits, ADataLink); 844 FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self); 439 845 end; 440 846 … … 450 856 end; 451 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 452 1043 { TSVGRectangle } 453 1044 … … 513 1104 514 1105 constructor TSVGRectangle.Create(ADocument: TXMLDocument; 515 AUnits: TCSSUnitConverter); 516 begin 1106 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1107 begin 1108 inherited Create(ADocument, AUnits, ADataLink); 517 1109 Init(ADocument,'rect',AUnits); 518 1110 end; 519 1111 520 1112 procedure TSVGRectangle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); 1113 var 1114 vx,vy,vw,vh: Single; 521 1115 begin 522 1116 if not isStrokeNone or not isFillNone then 523 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; 524 1122 ACanvas2d.beginPath; 525 ACanvas2d.roundRect(Units.ConvertWidth(x,AUnit).value,Units.ConvertWidth(y,AUnit).value, 526 Units.ConvertWidth(width,AUnit).value,Units.ConvertWidth(height,AUnit).value, 527 Units.ConvertWidth(rx,AUnit).value,Units.ConvertWidth(ry,AUnit).value); 1123 ACanvas2d.roundRect(vx,vy, vw,vh, 1124 Units.ConvertWidth(rx,AUnit).value,Units.ConvertHeight(ry,AUnit).value); 1125 if Assigned(GradientElement) then 1126 InitializeGradient(ACanvas2d, PointF(vx,vy),vw,vh,AUnit); 528 1127 if not isFillNone then 529 1128 begin 530 A Canvas2d.fillStyle(fillColor);1129 ApplyFillStyle(ACanvas2D,AUnit); 531 1130 ACanvas2d.fill; 532 1131 end; … … 544 1143 begin 545 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; 546 1152 end; 547 1153 … … 570 1176 result[i].y := parser.ParseFloat; 571 1177 end; 1178 parser.Free; 572 1179 end; 573 1180 … … 589 1196 end; 590 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; 591 1227 end; 592 1228 593 1229 constructor TSVGPolypoints.Create(ADocument: TXMLDocument; 594 AUnits: TCSSUnitConverter; AClosed: boolean); 595 begin 1230 AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink); 1231 begin 1232 inherited Create(ADocument, AUnits, ADataLink); 596 1233 if AClosed then 597 1234 Init(ADocument, 'polygon', AUnits) … … 608 1245 var 609 1246 prevMatrix: TAffineMatrix; 1247 pts: ArrayOfTPointF; 610 1248 begin 611 1249 if isFillNone and isStrokeNone then exit; … … 620 1258 begin 621 1259 ACanvas2d.beginPath; 622 ACanvas2d.polylineTo(pointsF); 1260 pts := pointsF; 1261 ACanvas2d.polylineTo(pts); 623 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 624 1268 if not isFillNone then 625 1269 begin 626 A Canvas2d.fillStyle(fillColor);1270 ApplyFillStyle(ACanvas2D,AUnit); 627 1271 ACanvas2d.fill; 628 1272 end; … … 649 1293 end; 650 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 651 1305 function TSVGPath.GetData: string; 652 1306 begin … … 668 1322 else 669 1323 FPath.SvgString := AValue; 1324 FBoundingBoxComputed := false; 670 1325 end; 671 1326 … … 676 1331 end; 677 1332 678 constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); 679 begin 1333 constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1334 begin 1335 inherited Create(ADocument, AUnits, ADataLink); 680 1336 Init(ADocument,'path',AUnits); 681 1337 FPath := nil; 1338 FBoundingBoxComputed := false; 1339 FBoundingBox := rectF(0,0,0,0); 682 1340 end; 683 1341 684 1342 constructor TSVGPath.Create(ADocument: TXMLDocument; AElement: TDOMElement; 685 AUnits: TCSSUnitConverter); 686 begin 1343 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1344 begin 1345 inherited Create(ADocument, AElement, AUnits, ADataLink); 687 1346 Init(ADocument, AElement, AUnits); 688 1347 FPath := nil; 1348 FBoundingBoxComputed := false; 1349 FBoundingBox := rectF(0,0,0,0); 689 1350 end; 690 1351 … … 710 1371 begin 711 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); 712 1377 if not isFillNone then 713 1378 begin 714 A Canvas2d.fillStyle(fillColor);1379 ApplyFillStyle(ACanvas2D,AUnit); 715 1380 ACanvas2d.fill; 716 1381 end; … … 766 1431 767 1432 constructor TSVGEllipse.Create(ADocument: TXMLDocument; 768 AUnits: TCSSUnitConverter); 769 begin 1433 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1434 begin 1435 inherited Create(ADocument, AUnits, ADataLink); 770 1436 Init(ADocument,'ellipse',AUnits); 771 1437 end; 772 1438 773 1439 procedure TSVGEllipse.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); 1440 var 1441 vcx,vcy,vrx,vry: Single; 774 1442 begin 775 1443 if not isFillNone or not isStrokeNone then 776 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; 777 1449 ACanvas2d.beginPath; 778 ACanvas2d.ellipse(Units.ConvertWidth(cx,AUnit).value,Units.ConvertWidth(cy,AUnit).value, 779 Units.ConvertWidth(rx,AUnit).value,Units.ConvertWidth(ry,AUnit).value); 1450 ACanvas2d.ellipse(vcx,vcy,vrx,vry); 1451 if Assigned(GradientElement) then 1452 InitializeGradient(ACanvas2d, PointF(vcx-vrx,vcy-vry),vrx*2,vry*2,AUnit); 780 1453 if not isFillNone then 781 1454 begin 782 A Canvas2d.fillStyle(fillColor);1455 ApplyFillStyle(ACanvas2D,AUnit); 783 1456 ACanvas2d.fill; 784 1457 end; … … 823 1496 end; 824 1497 825 constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); 826 begin 1498 constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1499 begin 1500 inherited Create(ADocument, AUnits, ADataLink); 827 1501 Init(ADocument,'circle',AUnits); 828 1502 end; 829 1503 830 1504 procedure TSVGCircle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); 1505 var 1506 vcx,vcy,vr: Single; 831 1507 begin 832 1508 if not isFillNone or not isStrokeNone then 833 1509 begin 1510 vcx:= Units.ConvertWidth(cx,AUnit).value; 1511 vcy:= Units.ConvertHeight(cy,AUnit).value; 1512 vr:= Units.ConvertWidth(r,AUnit).value; 834 1513 ACanvas2d.beginPath; 835 ACanvas2d.circle(Units.ConvertWidth(cx,AUnit).value,Units.ConvertWidth(cy,AUnit).value, 836 Units.ConvertWidth(r,AUnit).value); 1514 ACanvas2d.circle(vcx,vcy,vr); 1515 if Assigned(GradientElement) then 1516 InitializeGradient(ACanvas2d, PointF(vcx-vr,vcy-vr),vr*2,vr*2,AUnit); 837 1517 if not isFillNone then 838 1518 begin 839 A Canvas2d.fillStyle(fillColor);1519 ApplyFillStyle(ACanvas2D,AUnit); 840 1520 ACanvas2d.fill; 841 1521 end; … … 890 1570 end; 891 1571 892 constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter); 893 begin 1572 constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1573 begin 1574 inherited Create(ADocument, AUnits, ADataLink); 894 1575 Init(ADocument,'line',AUnits); 895 1576 end; … … 901 1582 ApplyStrokeStyle(ACanvas2D,AUnit); 902 1583 ACanvas2d.beginPath; 903 ACanvas2d.moveTo(Units.ConvertWidth(x1,AUnit).value,Units.Convert Width(y1,AUnit).value);904 ACanvas2d.lineTo(Units.ConvertWidth(x2,AUnit).value,Units.Convert Width(y2,AUnit).value);1584 ACanvas2d.moveTo(Units.ConvertWidth(x1,AUnit).value,Units.ConvertHeight(y1,AUnit).value); 1585 ACanvas2d.lineTo(Units.ConvertWidth(x2,AUnit).value,Units.ConvertHeight(y2,AUnit).value); 905 1586 ACanvas2d.stroke; 906 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; 907 1926 end; 908 1927 … … 948 1967 949 1968 constructor TSVGContent.Create(ADocument: TXMLDocument; AElement: TDOMElement; 950 AUnits: TCSSUnitConverter );1969 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement); 951 1970 var cur: TDOMNode; 952 1971 begin 953 1972 FDoc := ADocument; 954 1973 FDomElem := AElement; 955 FElements := TList.Create; 1974 FDataLink := ADataLink; 1975 FElements := TFPList.Create; 956 1976 FUnits := AUnits; 957 1977 cur := FDomElem.FirstChild; … … 959 1979 begin 960 1980 if cur is TDOMElement then 961 FElements.Add(CreateSVGElementFromNode(ADocument,TDOMElement(cur),FUnits)); 1981 FElements.Add(CreateSVGElementFromNode( 1982 ADocument,TDOMElement(cur),FUnits,ADataLink,ADataParent)); 962 1983 cur := cur.NextSibling; 963 1984 end; … … 971 1992 FreeAndNil(FElements); 972 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; 973 2002 end; 974 2003 … … 996 2025 ): TSVGLine; 997 2026 begin 998 result := TSVGLine.Create(FDoc,Units );2027 result := TSVGLine.Create(FDoc,Units,FDataLink); 999 2028 result.x1 := FloatWithCSSUnit(x1,AUnit); 1000 2029 result.y1 := FloatWithCSSUnit(y1,AUnit); … … 1014 2043 if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then 1015 2044 begin 1016 result := TSVGCircle.Create(FDoc,Units );2045 result := TSVGCircle.Create(FDoc,Units,FDataLink); 1017 2046 result.cx := FloatWithCSSUnit(Units.Convert(cx,AUnit,cuCustom,Units.DpiX),cuCustom); 1018 2047 result.cy := FloatWithCSSUnit(Units.Convert(cy,AUnit,cuCustom,Units.DpiY),cuCustom); … … 1022 2051 end else 1023 2052 begin 1024 result := TSVGCircle.Create(FDoc,Units );2053 result := TSVGCircle.Create(FDoc,Units,FDataLink); 1025 2054 result.cx := FloatWithCSSUnit(cx,AUnit); 1026 2055 result.cy := FloatWithCSSUnit(cy,AUnit); … … 1039 2068 ): TSVGEllipse; 1040 2069 begin 1041 result := TSVGEllipse.Create(FDoc,Units );2070 result := TSVGEllipse.Create(FDoc,Units,FDataLink); 1042 2071 result.cx := FloatWithCSSUnit(cx,AUnit); 1043 2072 result.cy := FloatWithCSSUnit(cy,AUnit); … … 1062 2091 end else 1063 2092 begin 1064 result := TSVGPath.Create(FDoc,Units );2093 result := TSVGPath.Create(FDoc,Units,FDataLink); 1065 2094 result.d := data; 1066 2095 AppendElement(result); … … 1072 2101 if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then 1073 2102 begin 1074 result := TSVGPath.Create(FDoc,Units );2103 result := TSVGPath.Create(FDoc,Units,FDataLink); 1075 2104 result.path.scale(Units.Convert(1,AUnit,cuCustom,Units.DpiX)); 1076 2105 path.copyTo(result.path); … … 1079 2108 end else 1080 2109 begin 1081 result := TSVGPath.Create(FDoc,Units );2110 result := TSVGPath.Create(FDoc,Units,FDataLink); 1082 2111 result.path.scale(Units.ConvertWidth(1,AUnit,cuCustom)); 1083 2112 path.copyTo(result.path); … … 1092 2121 i: integer; 1093 2122 begin 1094 result := TSVGPolypoints.Create(FDoc,FUnits,true );2123 result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink); 1095 2124 setlength(pts, length(points) div 2); 1096 2125 for i := 0 to high(pts) do … … 1106 2135 i: integer; 1107 2136 begin 1108 result := TSVGPolypoints.Create(FDoc,FUnits,true );2137 result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink); 1109 2138 setlength(pts, length(points)); 1110 2139 for i := 0 to high(pts) do … … 1117 2146 ): TSVGRectangle; 1118 2147 begin 1119 result := TSVGRectangle.Create(FDoc,Units );2148 result := TSVGRectangle.Create(FDoc,Units,FDataLink); 1120 2149 result.x := FloatWithCSSUnit(x,AUnit); 1121 2150 result.y := FloatWithCSSUnit(y,AUnit); … … 1134 2163 ): TSVGText; 1135 2164 begin 1136 result := TSVGText.Create(FDoc,Units );2165 result := TSVGText.Create(FDoc,Units,FDataLink); 1137 2166 result.x := FloatWithCSSUnit(x,AUnit); 1138 2167 result.y := FloatWithCSSUnit(y,AUnit); … … 1150 2179 AUnit: TCSSUnit): TSVGRectangle; 1151 2180 begin 1152 result := TSVGRectangle.Create(FDoc,Units );2181 result := TSVGRectangle.Create(FDoc,Units,FDataLink); 1153 2182 result.x := FloatWithCSSUnit(x,AUnit); 1154 2183 result.y := FloatWithCSSUnit(y,AUnit);
Note:
See TracChangeset
for help on using the changeset viewer.