Changeset 521 for GraphicTest/Packages/bgrabitmap/bgrasvgtype.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/bgrasvgtype.pas
r494 r521 2 2 3 3 {$mode objfpc}{$H+} 4 {$MODESWITCH ADVANCEDRECORDS} 4 5 5 6 interface … … 7 8 uses 8 9 Classes, SysUtils, BGRATransform, BGRABitmapTypes, BGRAUnits, 9 laz2_DOM, BGRACanvas2D ;10 laz2_DOM, BGRACanvas2D, fgl, BGRAGraphics; 10 11 11 12 type 13 ArrayOfFloat = array of single; 14 12 15 TSVGElement = class; 16 TSVGElementList = specialize TFPGList<TSVGElement>; 13 17 TSVGFactory = class of TSVGElement; 18 19 TSVGFillMode = ( 20 sfmEvenOdd = Ord(fmAlternate), 21 sfmNonZero = Ord(fmWinding) 22 ); 23 24 TFindStyleState = (fssNotSearch, 25 fssNotFind, 26 fssFind); 27 TStyleAttribute = record 28 attr : string; 29 pos : integer; 30 end; 31 ArrayOfTStyleAttribute = array of TStyleAttribute; 32 33 { TSVGPreserveAspectRatio } 34 35 TSVGPreserveAspectRatio = record 36 Preserve, Slice: boolean; 37 HorizAlign: TAlignment; 38 VertAlign: TTextLayout; 39 function ToString: string; 40 class function Parse(AValue: string): TSVGPreserveAspectRatio; static; 41 class function DefaultValue: TSVGPreserveAspectRatio; static; 42 end; 43 44 TSVGRecomputeEvent = procedure(Sender: TObject) of object; 45 46 { TSVGDataLink } 47 48 TSVGDataLink = class 49 private 50 FElements, 51 FGradients, 52 FStyles, 53 FRootElements: TSVGElementList; 54 function IsValidID(const id: integer; list: TSVGElementList): boolean; 55 function GetElement(id: integer): TSVGElement; 56 function GetGradient(id: integer): TSVGElement; 57 function GetStyle(id: integer): TSVGElement; 58 function GetRootElement(id: integer): TSVGElement; 59 function FindElement(el: TSVGElement; list: TSVGElementList): integer; 60 function Find(el: TSVGElement): integer;//(find on FElements) 61 procedure InternalLink(const id: integer; parent: TSVGElement); 62 procedure InternalUnLink(const id: integer); 63 procedure InternalReLink(const id: integer; parent: TSVGElement); 64 public 65 constructor Create; 66 destructor Destroy; override; 67 68 function ElementCount: integer; 69 function GradientCount: integer; 70 function StyleCount: integer; 71 //contains the elements at the root of the link tree (having parent = nil) 72 function RootElementCount: integer; 73 function IsLink(el: TSVGElement): boolean; 74 //(Note: assumes that the valid parent is present in the list or added later) 75 function Link(el: TSVGElement; parent: TSVGElement = nil): integer; 76 //excludes el from the list (+ restores validity of links) 77 procedure Unlink(el: TSVGElement); 78 //(faster method than a "for.. Unlink()") 79 procedure UnlinkAll; 80 //Method needed to change the parent of an item without removing it 81 function ReLink(el: TSVGElement; parent: TSVGElement): boolean; 82 83 //(useful for testing support) 84 function GetInternalState: TStringList; 85 86 property Elements[ID: integer]: TSVGElement read GetElement; 87 property Gradients[ID: integer]: TSVGElement read GetGradient; 88 property Styles[ID: integer]: TSVGElement read GetStyle; 89 property RootElements[ID: integer]: TSVGElement read GetRootElement; 90 end; 14 91 15 92 { TSVGElement } … … 17 94 TSVGElement = class 18 95 private 19 function GetAttributeOrStyle(AName: string): string; 96 findStyleState: TFindStyleState; 97 styleAttributes: ArrayOfTStyleAttribute; 98 FDataParent: TSVGElement; 99 FDataChildList: TSVGElementList; 100 function GetAttributeOrStyle(AName,ADefault: string): string; overload; 101 function GetAttributeOrStyle(AName: string): string; overload; 20 102 function GetFill: string; 21 103 function GetFillColor: TBGRAPixel; 22 104 function GetFillOpacity: single; 23 function GetHorizAttributeOrStyleWithUnit(AName: string 24 ): TFloatWithCSSUnit; 105 function GetFillRule: string; 106 function GetHorizAttributeOrStyleWithUnit(AName: string; 107 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 25 108 function GetIsFillNone: boolean; 26 109 function GetIsStrokeNone: boolean; 27 110 function GetMatrix(AUnit: TCSSUnit): TAffineMatrix; 28 111 function GetOpacity: single; 29 function GetOrthoAttributeOrStyleWithUnit(AName: string 30 ): TFloatWithCSSUnit;112 function GetOrthoAttributeOrStyleWithUnit(AName: string; 113 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 31 114 function GetStroke: string; 32 115 function GetStrokeColor: TBGRAPixel; … … 36 119 function GetStrokeOpacity: single; 37 120 function GetStrokeWidth: TFloatWithCSSUnit; 38 function GetStyle(const AName: string): string; 121 function GetStrokeDashArray: string; 122 function GetStrokeDashArrayF: ArrayOfFloat; 123 function GetStrokeDashOffset: TFloatWithCSSUnit; 124 function GetStyle(const AName,ADefault: string): string; overload; 125 function GetStyle(const AName: string): string; overload; 39 126 function GetTransform: string; 40 127 function GetUnits: TCSSUnitConverter; 41 function GetAttribute(AName: string): string; 42 function GetVerticalAttributeOrStyleWithUnit(AName: string 43 ): TFloatWithCSSUnit; 128 function GetAttribute(AName,ADefault: string; ACanInherit: boolean): string; overload; 129 function GetAttribute(AName,ADefault: string): string; overload; 130 function GetAttribute(AName: string): string; overload; 131 function GetVerticalAttributeOrStyleWithUnit(AName: string; 132 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 44 133 procedure SetAttribute(AName: string; AValue: string); 45 function GetAttributeWithUnit(AName: string): TFloatWithCSSUnit; 46 function GetAttributeOrStyleWithUnit(AName: string): TFloatWithCSSUnit; 47 function GetOrthoAttributeWithUnit(AName: string): TFloatWithCSSUnit; 48 function GetHorizAttributeWithUnit(AName: string): TFloatWithCSSUnit; 49 function GetVerticalAttributeWithUnit(AName: string): TFloatWithCSSUnit; 134 function GetAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload; 135 function GetAttributeWithUnit(AName: string): TFloatWithCSSUnit; overload; 136 function GetAttributeOrStyleWithUnit(AName: string; 137 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload; 138 function GetAttributeOrStyleWithUnit(AName: string): TFloatWithCSSUnit; overload; 139 function GetOrthoAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload; 140 function GetOrthoAttributeWithUnit(AName: string): TFloatWithCSSUnit; overload; 141 function GetHorizAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload; 142 function GetHorizAttributeWithUnit(AName: string): TFloatWithCSSUnit; overload; 143 function GetVerticalAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; overload; 144 function GetVerticalAttributeWithUnit(AName: string): TFloatWithCSSUnit; overload; 145 function GetID: string; 146 function GetClassAt: string; 50 147 procedure SetAttributeWithUnit(AName: string; AValue: TFloatWithCSSUnit); 51 148 procedure SetFill(AValue: string); 52 149 procedure SetFillColor(AValue: TBGRAPixel); 53 150 procedure SetFillOpacity(AValue: single); 151 procedure SetFillRule(AValue: string); 54 152 procedure SetHorizAttributeWithUnit(AName: string; AValue: TFloatWithCSSUnit); 55 153 procedure SetMatrix(AUnit: TCSSUnit; const AValue: TAffineMatrix); … … 62 160 procedure SetStrokeOpacity(AValue: single); 63 161 procedure SetStrokeWidth(AValue: TFloatWithCSSUnit); 162 procedure SetStrokeDashArray(AValue: string); 163 procedure SetStrokeDashArrayF(AValue: ArrayOfFloat); 164 procedure SetStrokeDashOffset(AValue: TFloatWithCSSUnit); 64 165 procedure SetStyle(AName: string; AValue: string); 65 166 procedure SetTransform(AValue: string); 66 167 procedure SetVerticalAttributeWithUnit(AName: string; AValue: TFloatWithCSSUnit); 67 168 procedure SetOrthoAttributeWithUnit(AName: string; AValue: TFloatWithCSSUnit); 169 procedure SetID(AValue: string); 170 procedure SetClassAt(AValue: string); 171 function FindStyleElementInternal(const classStr: string; 172 out attributesStr: string): integer; 173 procedure FindStyleElement; 68 174 protected 175 FDataLink: TSVGDataLink; 69 176 FDomElem: TDOMElement; 70 177 FUnits: TCSSUnitConverter; … … 74 181 procedure InternalDraw({%H-}ACanvas2d: TBGRACanvas2D; {%H-}AUnit: TCSSUnit); virtual; 75 182 procedure LocateStyleDeclaration(AText: string; AProperty: string; out AStartPos,AColonPos,AValueLength: integer); 183 procedure ApplyFillStyle(ACanvas2D: TBGRACanvas2D; {%H-}AUnit: TCSSUnit); virtual; 76 184 procedure ApplyStrokeStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit); 185 procedure Initialize; virtual; 77 186 public 78 constructor Create({%H-}ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter); virtual; 79 constructor Create({%H-}ADocument: TXMLDocument; {%H-}AUnits: TCSSUnitConverter); virtual; 187 constructor Create({%H-}ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; virtual; 188 constructor Create({%H-}ADocument: TXMLDocument; {%H-}AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; virtual; 189 destructor Destroy; override; 190 procedure Recompute; virtual; 80 191 procedure Draw({%H-}ACanvas2d: TBGRACanvas2D; {%H-}AUnit: TCSSUnit); 81 192 procedure fillNone; … … 83 194 procedure transformNone; 84 195 procedure RemoveStyle(const AName: string); 196 function HasAttribute(AName: string): boolean; 197 function fillMode: TSVGFillMode; 198 function DataChildList: TSVGElementList; 199 property DataLink: TSVGDataLink read FDataLink write FDataLink; 200 property AttributeDef[AName,ADefault: string]: string read GetAttribute; 85 201 property Attribute[AName: string]: string read GetAttribute write SetAttribute; 202 property AttributeOrStyleDef[AName,ADefault: string]: string read GetAttributeOrStyle; 86 203 property AttributeOrStyle[AName: string]: string read GetAttributeOrStyle; 204 property StyleDef[AName,ADefault: string]: string read GetStyle; 87 205 property Style[AName: string]: string read GetStyle write SetStyle; 206 property AttributeWithUnitDef[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetAttributeWithUnit; 207 property AttributeWithUnit[AName: string]: TFloatWithCSSUnit read GetAttributeWithUnit write SetAttributeWithUnit; 208 property OrthoAttributeWithUnitDef[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetOrthoAttributeWithUnit; 88 209 property OrthoAttributeWithUnit[AName: string]: TFloatWithCSSUnit read GetOrthoAttributeWithUnit write SetOrthoAttributeWithUnit; 210 property HorizAttributeWithUnitDef[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetHorizAttributeWithUnit; 89 211 property HorizAttributeWithUnit[AName: string]: TFloatWithCSSUnit read GetHorizAttributeWithUnit write SetHorizAttributeWithUnit; 212 property VerticalAttributeWithUnitDef[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetVerticalAttributeWithUnit; 90 213 property VerticalAttributeWithUnit[AName: string]: TFloatWithCSSUnit read GetVerticalAttributeWithUnit write SetVerticalAttributeWithUnit; 91 property OrthoAttributeOrStyleWithUnit[AName: string ]: TFloatWithCSSUnit read GetOrthoAttributeOrStyleWithUnit;92 property HorizAttributeOrStyleWithUnit[AName: string ]: TFloatWithCSSUnit read GetHorizAttributeOrStyleWithUnit;93 property VerticalAttributeOrStyleWithUnit[AName: string ]: TFloatWithCSSUnit read GetVerticalAttributeOrStyleWithUnit;214 property OrthoAttributeOrStyleWithUnit[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetOrthoAttributeOrStyleWithUnit; 215 property HorizAttributeOrStyleWithUnit[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetHorizAttributeOrStyleWithUnit; 216 property VerticalAttributeOrStyleWithUnit[AName: string; ADefault: TFloatWithCSSUnit]: TFloatWithCSSUnit read GetVerticalAttributeOrStyleWithUnit; 94 217 property DOMElement: TDOMElement read GetDOMElement; 95 218 property Units: TCSSUnitConverter read GetUnits; … … 105 228 property strokeLineJoin: string read GetStrokeLineJoin write SetStrokeLineJoin; 106 229 property strokeLineCap: string read GetStrokeLineCap write SetStrokeLineCap; 230 property strokeDashArray: string read GetStrokeDashArray write SetStrokeDashArray; 231 property strokeDashArrayF: ArrayOfFloat read GetStrokeDashArrayF write SetStrokeDashArrayF; 232 property strokeDashOffset: TFloatWithCSSUnit read GetStrokeDashOffset write SetStrokeDashOffset; 107 233 property fill: string read GetFill write SetFill; 108 234 property fillColor: TBGRAPixel read GetFillColor write SetFillColor; 109 235 property fillOpacity: single read GetFillOpacity write SetFillOpacity; 236 property fillRule: string read GetFillRule write SetFillRule; 110 237 property opacity: single read GetOpacity write SetOpacity; 238 property ID: string read GetID write SetID; 239 property classAt: string read GetClassAt write SetClassAt;//Attribute "class" 240 property DataParent: TSVGElement read FDataParent write FDataParent; 111 241 end; 112 242 … … 125 255 function ParseId: string; 126 256 function ParseSymbol: char; 257 function ParseTransform: TAffineMatrix; 127 258 procedure SkipSymbol(ASymbol: char); 128 259 procedure SkipUpToSymbol(ASymbol:char); … … 133 264 property Done: boolean read GetDone; 134 265 end; 266 267 resourcestring 268 rsInvalidId = 'invalid id'; 135 269 136 270 implementation 271 272 uses BGRASVGShapes; 273 274 { TSVGPreserveAspectRatio } 275 276 function TSVGPreserveAspectRatio.ToString: string; 277 begin 278 if not Preserve then result := 'none' else 279 begin 280 result := ''; 281 case HorizAlign of 282 taCenter: result += 'xMid'; 283 taRightJustify: result += 'xMax'; 284 else result += 'xMin'; 285 end; 286 case VertAlign of 287 tlCenter: result += 'YMid'; 288 tlBottom: result += 'YMax'; 289 else result += 'YMin'; 290 end; 291 if Slice then result += ' slice' else result += ' meet'; 292 end; 293 end; 294 295 class function TSVGPreserveAspectRatio.Parse(AValue: string 296 ): TSVGPreserveAspectRatio; 297 var p: TSVGParser; 298 id: string; 299 begin 300 p := TSVGParser.Create(AValue); 301 result := DefaultValue; 302 repeat 303 id := p.ParseId; 304 if id = 'none' then 305 begin 306 result.Preserve := false; 307 //set other parameters for intermediate value of ViewSize (before stretching non-proportionaly) 308 result.Slice := false; 309 result.HorizAlign := taCenter; 310 result.VertAlign := tlCenter; 311 exit; 312 end else 313 if id = 'slice' then result.Slice := true 314 else if (length(id)=8) and (id[1] = 'x') and (id[5] = 'Y') then 315 begin 316 case copy(id,2,3) of 317 'Min': result.HorizAlign := taLeftJustify; 318 'Mid': result.HorizAlign := taCenter; 319 'Max': result.HorizAlign := taRightJustify; 320 end; 321 case copy(id,6,3) of 322 'Min': result.VertAlign := tlTop; 323 'Mid': result.VertAlign := tlCenter; 324 'Max': result.VertAlign := tlBottom; 325 end; 326 end; 327 until id = ''; 328 p.Free; 329 end; 330 331 class function TSVGPreserveAspectRatio.DefaultValue: TSVGPreserveAspectRatio; 332 begin 333 result.Preserve := true; 334 result.Slice := false; 335 result.HorizAlign := taCenter; 336 result.VertAlign := tlCenter; 337 end; 137 338 138 339 { TSVGParser } … … 194 395 end; 195 396 397 function TSVGParser.ParseTransform: TAffineMatrix; 398 var 399 kind: String; 400 m : TAffineMatrix; 401 angle,tx,ty: single; 402 begin 403 result := AffineMatrixIdentity; 404 while not Done do 405 begin 406 kind := ParseId; 407 if kind = '' then break; 408 if ParseSymbol <> '(' then break; 409 if compareText(kind,'matrix')=0 then 410 begin 411 m[1,1] := ParseFloat; 412 SkipSymbol(','); 413 m[2,1] := ParseFloat; 414 SkipSymbol(','); 415 m[1,2] := ParseFloat; 416 SkipSymbol(','); 417 m[2,2] := ParseFloat; 418 SkipSymbol(','); 419 m[1,3] := ParseFloat; 420 SkipSymbol(','); 421 m[2,3] := ParseFloat; 422 result *= m; 423 end else 424 if compareText(kind,'translate')=0 then 425 begin 426 tx := ParseFloat; 427 SkipSymbol(','); 428 ty := ParseFloat; 429 result *= AffineMatrixTranslation(tx,ty); 430 end else 431 if compareText(kind,'scale')=0 then 432 begin 433 tx := ParseFloat; 434 SkipSymbol(','); 435 ClearError; 436 ty := ParseFloat; 437 if NumberError then ty := tx; 438 result *= AffineMatrixScale(tx,ty); 439 end else 440 if compareText(kind,'rotate')=0 then 441 begin 442 angle := ParseFloat; 443 SkipSymbol(','); 444 tx := ParseFloat; 445 SkipSymbol(','); 446 ty := ParseFloat; 447 result *= AffineMatrixTranslation(tx,ty)*AffineMatrixRotationDeg(angle)* 448 AffineMatrixTranslation(-tx,-ty); 449 end else 450 if compareText(kind,'skewx')=0 then 451 begin 452 angle := ParseFloat; 453 result *= AffineMatrixSkewXDeg(angle); 454 end else 455 if compareText(kind,'skewy')=0 then 456 begin 457 angle := ParseFloat; 458 result *= AffineMatrixSkewYDeg(angle); 459 end; 460 SkipUpToSymbol(')'); 461 end; 462 end; 463 196 464 procedure TSVGParser.SkipSymbol(ASymbol: char); 197 465 begin … … 211 479 end; 212 480 481 { TSVGDataLink } 482 483 constructor TSVGDataLink.Create; 484 begin 485 FElements:= TSVGElementList.Create; 486 FGradients:= TSVGElementList.Create; 487 FStyles:= TSVGElementList.Create; 488 FRootElements:= TSVGElementList.Create; 489 end; 490 491 destructor TSVGDataLink.Destroy; 492 begin 493 FreeAndNil(FRootElements); 494 FreeAndNil(FGradients); 495 FreeAndNil(FElements); 496 FreeAndNil(FStyles); 497 inherited Destroy; 498 end; 499 500 function TSVGDataLink.IsValidID(const id: integer; list: TSVGElementList): boolean; 501 begin 502 result:= (id >= 0) and (id < list.Count); 503 end; 504 505 function TSVGDataLink.GetElement(id: integer): TSVGElement; 506 begin 507 if not IsValidID(id,FElements) then 508 raise exception.Create(rsInvalidId); 509 result:= FElements[id]; 510 end; 511 512 function TSVGDataLink.GetGradient(id: integer): TSVGElement; 513 begin 514 if not IsValidID(id,FGradients) then 515 raise exception.Create(rsInvalidId); 516 result:= FGradients[id]; 517 end; 518 519 function TSVGDataLink.GetStyle(id: integer): TSVGElement; 520 begin 521 if not IsValidID(id,FStyles) then 522 raise exception.Create(rsInvalidId); 523 result:= FStyles[id]; 524 end; 525 526 function TSVGDataLink.GetRootElement(id: integer): TSVGElement; 527 begin 528 if not IsValidID(id,FRootElements) then 529 raise exception.Create(rsInvalidId); 530 result:= FRootElements[id]; 531 end; 532 533 function TSVGDataLink.FindElement(el: TSVGElement; list: TSVGElementList): integer; 534 var 535 i: integer; 536 begin 537 for i:= 0 to list.Count-1 do 538 if list[i] = el then 539 begin 540 result:= i; 541 Exit; 542 end; 543 result:= -1; 544 end; 545 546 function TSVGDataLink.Find(el: TSVGElement): integer; 547 begin 548 result:= FindElement(el,FElements); 549 end; 550 551 procedure TSVGDataLink.InternalLink(const id: integer; parent: TSVGElement); 552 var 553 el: TSVGElement; 554 begin 555 el:= FElements.Items[id]; 556 with el do 557 begin 558 DataParent:= parent; 559 if parent = nil then 560 FRootElements.Add(el); 561 //Update DataChildList of "parent" before add it 562 //(not use el.DataChildList.Clear here!!) 563 if parent <> nil then 564 parent.DataChildList.Add(el); 565 end; 566 end; 567 568 procedure TSVGDataLink.InternalUnLink(const id: integer); 569 var 570 i,pos_root: integer; 571 el: TSVGElement; 572 begin 573 el:= FElements.Items[id]; 574 with el do 575 begin 576 //se root need remove (use pos for add child as new root) 577 if DataParent = nil then 578 pos_root:= FRootElements.Remove(el) 579 else 580 pos_root:= FRootElements.Count; 581 //i have to assign a parent of a upper level 582 //and update child list of new parent (if not nil) 583 with DataChildList do 584 begin 585 for i:= 0 to Count-1 do 586 begin 587 Items[i].DataParent:= el.DataParent; 588 if el.DataParent = nil then 589 //with parent nil = new root 590 FRootElements.Insert(pos_root+i, Items[i]) 591 else 592 el.DataParent.DataChildList.Add( Items[i] ); 593 end; 594 Clear; 595 end; 596 //if he has a parent, I have to remove his reference as a child 597 if DataParent <> nil then 598 begin 599 DataParent.DataChildList.Remove(el); 600 DataParent:= nil; 601 end; 602 end; 603 end; 604 605 procedure TSVGDataLink.InternalReLink(const id: integer; parent: TSVGElement); 606 begin 607 InternalUnLink(id); 608 InternalLink(id,parent); 609 end; 610 611 function TSVGDataLink.ElementCount: integer; 612 begin 613 result:= FElements.Count; 614 end; 615 616 function TSVGDataLink.GradientCount: integer; 617 begin 618 result:= FGradients.Count; 619 end; 620 621 function TSVGDataLink.StyleCount: integer; 622 begin 623 result:= FStyles.Count; 624 end; 625 626 function TSVGDataLink.RootElementCount: integer; 627 begin 628 result:= FRootElements.Count; 629 end; 630 631 function TSVGDataLink.IsLink(el: TSVGElement): boolean; 632 begin 633 result:= Find(el) <> -1; 634 end; 635 636 function TSVGDataLink.Link(el: TSVGElement; parent: TSVGElement = nil): integer; 637 begin 638 FElements.Add(el); 639 result:= FElements.Count-1; 640 InternalLink(result,parent); 641 if el is TSVGGradient then 642 FGradients.Add(el) 643 else if el is TSVGStyle then 644 FStyles.Add(el); 645 end; 646 647 procedure TSVGDataLink.Unlink(el: TSVGElement); 648 var 649 id: integer; 650 begin 651 id:= FindElement(el,FElements); 652 if id <> -1 then 653 begin 654 if el is TSVGGradient then 655 FGradients.Remove(el) 656 else if el is TSVGStyle then 657 FStyles.Remove(el); 658 InternalUnLink(id); 659 FElements.Delete(id); 660 end 661 else 662 raise exception.Create('element not find'); 663 end; 664 665 procedure TSVGDataLink.UnlinkAll; 666 var 667 i: integer; 668 begin 669 FGradients.Clear; 670 FStyles.Clear; 671 672 for i:= 0 to FElements.Count-1 do 673 InternalUnLink(i); 674 FRootElements.Clear; 675 FElements.Clear; 676 end; 677 678 function TSVGDataLink.ReLink(el: TSVGElement; parent: TSVGElement): boolean; 679 var 680 id: integer; 681 begin 682 id:= FindElement(el,FElements); 683 if id <> -1 then 684 begin 685 result:= true; 686 if el.DataParent <> parent then 687 InternalReLink(id,parent); 688 end 689 else 690 result:= false; 691 end; 692 693 function TSVGDataLink.GetInternalState: TStringList; 694 var 695 nid: integer; 696 sl: TStringList; 697 698 function SpaceStr(const level: integer): string; 699 var 700 i: integer; 701 begin 702 result:= ''; 703 for i:= 1 to level do 704 result:= result + ' '; 705 end; 706 707 procedure AddStr(s: string; const level: integer); 708 begin 709 sl.Add( SpaceStr(level) + s ); 710 end; 711 712 function ElementIdentity(el: TSVGElement): string; 713 begin 714 if el = nil then 715 result:= 'nil' 716 else 717 begin 718 result:= el.ID; 719 if Trim(Result) = '' then 720 result:= 'unknow'; 721 result:= result + ' - ' + el.ClassName + 722 //(slow: for test ok) 723 ' | (pos: ' + IntToStr( Find(el) ) + ')'; 724 end; 725 end; 726 727 procedure ElementToInfo(el: TSVGElement; const level: integer); 728 Var 729 i: integer; 730 sep: string; 731 begin 732 if el.DataParent = nil then 733 sep:= '###' 734 else 735 sep:= '***'; 736 AddStr('{'+sep+' '+ElementIdentity(el)+' '+sep+'}', level); 737 AddStr('[Parent: ' + ElementIdentity(el.DataParent) + ']', level); 738 for i:= 0 to el.DataChildList.Count-1 do 739 AddStr('[Child: ' + ElementIdentity(el.DataChildList[i]) + ']', level); 740 end; 741 742 procedure BuildInfo(el: TSVGElement; const level: integer = 1); 743 const 744 kspace = 5; 745 var 746 i: Integer; 747 begin 748 ElementToInfo(el,level); 749 Inc(nid); 750 for i:= 0 to el.DataChildList.Count-1 do 751 BuildInfo(el.DataChildList[i],level+kspace); 752 end; 753 754 var 755 i: integer; 756 begin 757 nid:= 0; 758 sl:= TStringList.Create; 759 for i:= 0 to FRootElements.Count-1 do 760 BuildInfo( FRootElements[i] ); 761 result:= sl; 762 end; 763 213 764 { TSVGElement } 214 765 766 function TSVGElement.GetAttribute(AName,ADefault: string; ACanInherit: boolean): string; 767 var 768 curNode: TDOMElement; 769 begin 770 curNode := FDomElem; 771 repeat 772 result := Trim(curNode.GetAttribute(AName)); 773 if (result = 'currentColor') and (AName <> 'color') then 774 begin 775 AName := 'color'; 776 curNode := FDomElem; //get from the current element 777 ACanInherit:= true; 778 result := Trim(curNode.GetAttribute(AName)); 779 end; 780 if ((result = '') or (result = 'inherit')) and ACanInherit and 781 (curNode.ParentNode is TDOMElement) then 782 curNode := curNode.ParentNode as TDOMElement 783 else 784 curNode := nil; 785 until curNode = nil; 786 787 if (result = '') or (result = 'inherit') then 788 result:= ADefault; 789 end; 790 791 function TSVGElement.GetAttribute(AName, ADefault: string): string; 792 begin 793 result := GetAttribute(AName, ADefault, False); 794 end; 795 215 796 function TSVGElement.GetAttribute(AName: string): string; 216 797 begin 217 result := FDomElem.GetAttribute(AName);218 end; 219 220 function TSVGElement.GetVerticalAttributeOrStyleWithUnit(AName: string 221 ): TFloatWithCSSUnit;222 begin 223 result := GetAttributeOrStyleWithUnit(AName );798 result:= GetAttribute(AName,''); 799 end; 800 801 function TSVGElement.GetVerticalAttributeOrStyleWithUnit(AName: string; 802 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 803 begin 804 result := GetAttributeOrStyleWithUnit(AName,ADefault); 224 805 if result.CSSUnit <> cuCustom then 225 806 if units.DpiScaleY = 0 then … … 229 810 end; 230 811 812 function TSVGElement.GetAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 813 begin 814 result := TCSSUnitConverter.parseValue(Attribute[AName],ADefault); 815 end; 816 231 817 function TSVGElement.GetAttributeWithUnit(AName: string): TFloatWithCSSUnit; 232 818 begin 233 result := TCSSUnitConverter.parseValue(Attribute[AName],FloatWithCSSUnit(0,cuCustom));234 end; 235 236 function TSVGElement.GetAttributeOrStyleWithUnit(AName: string 237 ): TFloatWithCSSUnit; 238 varvalueText: string;819 result := GetAttributeWithUnit(AName,FloatWithCSSUnit(0,cuCustom)); 820 end; 821 822 function TSVGElement.GetAttributeOrStyleWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 823 var 824 valueText: string; 239 825 begin 240 826 valueText := Style[AName]; 241 if valueText = '' then valueText := Attribute[AName]; 242 result := TCSSUnitConverter.parseValue(valueText,FloatWithCSSUnit(0,cuCustom)); 243 end; 244 245 function TSVGElement.GetOrthoAttributeWithUnit(AName: string 246 ): TFloatWithCSSUnit; 247 begin 248 result := GetHorizAttributeWithUnit(AName); 827 if valueText = '' then 828 valueText := GetAttribute(AName,'',True); 829 result := TCSSUnitConverter.parseValue(valueText,ADefault); 830 end; 831 832 function TSVGElement.GetAttributeOrStyleWithUnit(AName: string): TFloatWithCSSUnit; 833 begin 834 result := GetAttributeOrStyleWithUnit(AName,FloatWithCSSUnit(0,cuCustom)); 835 end; 836 837 function TSVGElement.GetOrthoAttributeWithUnit(AName: string; 838 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 839 begin 840 result := GetHorizAttributeWithUnit(AName,ADefault); 249 841 //value will be inconsistent if scaling is inconsistent 250 842 end; 251 843 252 function TSVGElement.GetHorizAttributeWithUnit(AName: string 253 ): TFloatWithCSSUnit; 254 begin 255 result := GetAttributeWithUnit(AName); 844 function TSVGElement.GetOrthoAttributeWithUnit(AName: string): TFloatWithCSSUnit; 845 begin 846 result := GetOrthoAttributeWithUnit(AName,FloatWithCSSUnit(0,cuCustom)); 847 end; 848 849 function TSVGElement.GetHorizAttributeWithUnit(AName: string; 850 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 851 begin 852 result := GetAttributeWithUnit(AName,ADefault); 853 if result.value <> EmptySingle then 854 begin 855 if result.CSSUnit <> cuCustom then 856 if units.DpiScaleX = 0 then 857 result.value := 0 858 else 859 result.value /= Units.DpiScaleX; 860 end; 861 end; 862 863 function TSVGElement.GetHorizAttributeWithUnit(AName: string): TFloatWithCSSUnit; 864 begin 865 result := GetHorizAttributeWithUnit(AName,FloatWithCSSUnit(0,cuCustom)); 866 end; 867 868 function TSVGElement.GetAttributeOrStyle(AName,ADefault: string): string; 869 begin 870 result := GetStyle(AName,ADefault); 871 if result = '' then 872 result := GetAttribute(AName,ADefault,True); 873 end; 874 875 function TSVGElement.GetAttributeOrStyle(AName: string): string; 876 begin 877 result:= GetAttributeOrStyle(AName,''); 878 end; 879 880 function TSVGElement.GetFill: string; 881 begin 882 result := AttributeOrStyleDef['fill','black']; 883 end; 884 885 function TSVGElement.GetFillColor: TBGRAPixel; 886 begin 887 result := StrToBGRA(fill,BGRABlack); 888 result.alpha := round(result.alpha*fillOpacity*opacity); 889 if result.alpha = 0 then result := BGRAPixelTransparent; 890 end; 891 892 function TSVGElement.GetFillOpacity: single; 893 var errPos: integer; 894 begin 895 val(AttributeOrStyleDef['fill-opacity','1'], result, errPos); 896 if errPos <> 0 then result := 1 else 897 if result < 0 then result := 0 else 898 if result > 1 then result := 1; 899 end; 900 901 function TSVGElement.GetFillRule: string; 902 begin 903 result := AttributeOrStyleDef['fill-rule','nonzero']; 904 end; 905 906 function TSVGElement.GetHorizAttributeOrStyleWithUnit(AName: string; 907 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 908 begin 909 result := GetAttributeOrStyleWithUnit(AName,ADefault); 256 910 if result.CSSUnit <> cuCustom then 257 911 if units.DpiScaleX = 0 then … … 261 915 end; 262 916 263 function TSVGElement.GetAttributeOrStyle(AName: string): string; 264 begin 265 result := GetStyle(AName); 266 if result = '' then result := GetAttribute(AName); 267 end; 268 269 function TSVGElement.GetFill: string; 270 begin 271 result := AttributeOrStyle['fill']; 272 end; 273 274 function TSVGElement.GetFillColor: TBGRAPixel; 275 begin 276 result := StrToBGRA(fill,BGRABlack); 277 result.alpha := round(result.alpha*fillOpacity*opacity); 278 if result.alpha = 0 then result := BGRAPixelTransparent; 279 end; 280 281 function TSVGElement.GetFillOpacity: single; 917 function TSVGElement.GetIsFillNone: boolean; 918 begin 919 result := compareText(trim(fill),'none')=0; 920 end; 921 922 function TSVGElement.GetIsStrokeNone: boolean; 923 var strokeStr: string; 924 begin 925 strokeStr := stroke; 926 result := (trim(strokeStr)='') or (compareText(trim(strokeStr),'none')=0); 927 end; 928 929 function TSVGElement.GetMatrix(AUnit: TCSSUnit): TAffineMatrix; 930 var parser: TSVGParser; 931 s: string; 932 begin 933 s := transform; 934 if s='' then 935 begin 936 result := AffineMatrixIdentity; 937 exit; 938 end; 939 parser := TSVGParser.Create(s); 940 result := parser.ParseTransform; 941 result[1,3] := Units.ConvertWidth(result[1,3],cuCustom,AUnit); 942 result[2,3] := Units.ConvertHeight(result[2,3],cuCustom,AUnit); 943 parser.Free; 944 end; 945 946 function TSVGElement.GetOpacity: single; 282 947 var errPos: integer; 283 948 begin 284 val(AttributeOrStyle ['fill-opacity'], result, errPos);949 val(AttributeOrStyleDef['opacity','1'], result, errPos); 285 950 if errPos <> 0 then result := 1 else 286 951 if result < 0 then result := 0 else … … 288 953 end; 289 954 290 function TSVGElement.GetHorizAttributeOrStyleWithUnit(AName: string 291 ): TFloatWithCSSUnit; 292 begin 293 result := GetAttributeOrStyleWithUnit(AName); 294 if result.CSSUnit <> cuCustom then 295 if units.DpiScaleX = 0 then 296 result.value := 0 297 else 298 result.value /= Units.DpiScaleX; 299 end; 300 301 function TSVGElement.GetIsFillNone: boolean; 302 begin 303 result := compareText(trim(fill),'none')=0; 304 end; 305 306 function TSVGElement.GetIsStrokeNone: boolean; 307 var strokeStr: string; 308 begin 309 strokeStr := stroke; 310 result := (trim(strokeStr)='') or (compareText(trim(strokeStr),'none')=0); 311 end; 312 313 function TSVGElement.GetMatrix(AUnit: TCSSUnit): TAffineMatrix; 314 var parser: TSVGParser; 315 s,kind: string; 316 m : TAffineMatrix; 317 angle,tx,ty: single; 318 begin 319 result := AffineMatrixIdentity; 320 s := transform; 321 if s='' then exit; 322 parser := TSVGParser.Create(s); 323 while not parser.Done do 324 begin 325 kind := parser.ParseId; 326 if kind = '' then break; 327 if parser.ParseSymbol <> '(' then break; 328 if compareText(kind,'matrix')=0 then 329 begin 330 m[1,1] := parser.ParseFloat; 331 parser.SkipSymbol(','); 332 m[2,1] := parser.ParseFloat; 333 parser.SkipSymbol(','); 334 m[1,2] := parser.ParseFloat; 335 parser.SkipSymbol(','); 336 m[2,2] := parser.ParseFloat; 337 parser.SkipSymbol(','); 338 m[1,3] := parser.ParseFloat; 339 parser.SkipSymbol(','); 340 m[2,3] := parser.ParseFloat; 341 result *= m; 342 end else 343 if compareText(kind,'translate')=0 then 344 begin 345 tx := parser.ParseFloat; 346 parser.SkipSymbol(','); 347 ty := parser.ParseFloat; 348 result *= AffineMatrixTranslation(tx,ty); 349 end else 350 if compareText(kind,'scale')=0 then 351 begin 352 tx := parser.ParseFloat; 353 parser.SkipSymbol(','); 354 parser.ClearError; 355 ty := parser.ParseFloat; 356 if parser.NumberError then ty := tx; 357 result *= AffineMatrixScale(tx,ty); 358 end else 359 if compareText(kind,'rotate')=0 then 360 begin 361 angle := parser.ParseFloat; 362 parser.SkipSymbol(','); 363 tx := parser.ParseFloat; 364 parser.SkipSymbol(','); 365 ty := parser.ParseFloat; 366 result *= AffineMatrixTranslation(tx,ty)*AffineMatrixRotationDeg(angle)* 367 AffineMatrixTranslation(-tx,-ty); 368 end else 369 if compareText(kind,'skewx')=0 then 370 begin 371 angle := parser.ParseFloat; 372 result *= AffineMatrixSkewXDeg(angle); 373 end else 374 if compareText(kind,'skewy')=0 then 375 begin 376 angle := parser.ParseFloat; 377 result *= AffineMatrixSkewYDeg(angle); 378 end; 379 parser.SkipUpToSymbol(')'); 380 end; 381 parser.free; 382 result[1,3] := Units.ConvertWidth(result[1,3],cuCustom,AUnit); 383 result[2,3] := Units.ConvertHeight(result[2,3],cuCustom,AUnit); 384 end; 385 386 function TSVGElement.GetOpacity: single; 955 function TSVGElement.GetOrthoAttributeOrStyleWithUnit(AName: string; 956 ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 957 begin 958 result := GetHorizAttributeOrStyleWithUnit(AName,ADefault); 959 //value will be inconsistent if scaling is inconsistent 960 end; 961 962 function TSVGElement.GetStroke: string; 963 begin 964 result := AttributeOrStyleDef['stroke','none']; 965 end; 966 967 function TSVGElement.GetStrokeColor: TBGRAPixel; 968 begin 969 result := StrToBGRA(stroke); 970 result.alpha := round(result.alpha*strokeOpacity*opacity); 971 if result.alpha = 0 then result := BGRAPixelTransparent; 972 end; 973 974 function TSVGElement.GetStrokeLineCap: string; 975 begin 976 result := AttributeOrStyleDef['stroke-linecap','butt']; 977 end; 978 979 function TSVGElement.GetStrokeLineJoin: string; 980 begin 981 result := AttributeOrStyleDef['stroke-linejoin','miter']; 982 end; 983 984 function TSVGElement.GetStrokeMiterLimit: single; 387 985 var errPos: integer; 388 986 begin 389 val(AttributeOrStyle['opacity'], result, errPos); 987 val(AttributeOrStyleDef['stroke-miterlimit','4'], result, errPos); 988 if errPos <> 0 then result := 4 else 989 if result < 1 then result := 1; 990 end; 991 992 function TSVGElement.GetStrokeOpacity: single; 993 var errPos: integer; 994 begin 995 val(AttributeOrStyleDef['stroke-opacity','1'], result, errPos); 390 996 if errPos <> 0 then result := 1 else 391 997 if result < 0 then result := 0 else … … 393 999 end; 394 1000 395 function TSVGElement.GetOrthoAttributeOrStyleWithUnit(AName: string396 ): TFloatWithCSSUnit;397 begin398 result := GetHorizAttributeOrStyleWithUnit(AName);399 //value will be inconsistent if scaling is inconsistent400 end;401 402 function TSVGElement.GetStroke: string;403 begin404 result := AttributeOrStyle['stroke'];405 end;406 407 function TSVGElement.GetStrokeColor: TBGRAPixel;408 begin409 result := StrToBGRA(stroke);410 result.alpha := round(result.alpha*strokeOpacity*opacity);411 if result.alpha = 0 then result := BGRAPixelTransparent;412 end;413 414 function TSVGElement.GetStrokeLineCap: string;415 begin416 result := AttributeOrStyle['stroke-linecap'];417 if result = '' then result := 'butt';418 end;419 420 function TSVGElement.GetStrokeLineJoin: string;421 begin422 result := AttributeOrStyle['stroke-linejoin'];423 if result = '' then result := 'miter';424 end;425 426 function TSVGElement.GetStrokeMiterLimit: single;427 var errPos: integer;428 begin429 val(AttributeOrStyle['stroke-miterlimit'], result, errPos);430 if errPos <> 0 then result := 4 else431 if result < 1 then result := 1;432 end;433 434 function TSVGElement.GetStrokeOpacity: single;435 var errPos: integer;436 begin437 val(AttributeOrStyle['stroke-opacity'], result, errPos);438 if errPos <> 0 then result := 1 else439 if result < 0 then result := 0 else440 if result > 1 then result := 1;441 end;442 443 1001 function TSVGElement.GetStrokeWidth: TFloatWithCSSUnit; 444 1002 begin 445 result := OrthoAttributeOrStyleWithUnit['stroke-width']; 446 end; 1003 result := OrthoAttributeOrStyleWithUnit['stroke-width',FloatWithCSSUnit(1,cuCustom)]; 1004 end; 1005 1006 function TSVGElement.GetStrokeDashArray: string; 1007 begin 1008 result := AttributeDef['stroke-dasharray','none']; 1009 end; 1010 1011 function TSVGElement.GetStrokeDashArrayF: ArrayOfFloat; 1012 var 1013 parser: TSVGParser; 1014 nvalue,i: integer; 1015 s_array: String; 1016 begin 1017 s_array:= strokeDashArray; 1018 if s_array = 'none' then 1019 begin 1020 setlength(Result,0); 1021 exit; 1022 end; 1023 parser:=TSVGParser.Create(s_array); 1024 nvalue := 0; 1025 repeat 1026 parser.ParseFloat; 1027 if not parser.NumberError then 1028 inc(nvalue); 1029 until parser.NumberError or parser.Done; 1030 parser.ClearError; 1031 setlength(Result,nvalue); 1032 parser.Position := 1; 1033 for i := 0 to high(result) do 1034 result[i] := parser.ParseFloat; 1035 parser.Free; 1036 end; 1037 1038 function TSVGElement.GetStrokeDashOffset: TFloatWithCSSUnit; 1039 begin 1040 result := OrthoAttributeWithUnit['stroke-dashoffset']; 1041 end; 1042 1043 function TSVGElement.GetStyle(const AName,ADefault: string): string; 1044 1045 function GetInternal(const ruleset: string): string; 1046 var 1047 startPos, colonPos, valueLength: integer; 1048 begin 1049 LocateStyleDeclaration(ruleset, AName, startPos,colonPos, valueLength); 1050 if valueLength <> -1 then 1051 result := trim(copy(ruleset, colonPos+1, valueLength)) 1052 else 1053 result := ''; 1054 end; 1055 1056 var 1057 i: integer; 1058 begin 1059 result:= ''; 1060 1061 //Find on <style> block (priority!) 1062 //if "not search"..search 1063 if findStyleState = fssNotSearch then 1064 FindStyleElement; 1065 //if "find"..use 1066 if findStyleState <> fssNotFind then 1067 for i:= Length(styleAttributes)-1 downto 0 do 1068 begin 1069 result:= GetInternal(styleAttributes[i].attr); 1070 if result <> '' then 1071 Break; 1072 end; 1073 1074 if result = '' then 1075 result:= GetInternal( Attribute['style',ADefault] ); 1076 end; 447 1077 448 1078 function TSVGElement.GetStyle(const AName: string): string; 449 var 450 startPos, colonPos, valueLength: integer; 451 ruleset: string; 452 begin 453 ruleset := Attribute['style']; 454 LocateStyleDeclaration(ruleset, AName, startPos,colonPos, valueLength); 455 if valueLength <> -1 then 456 begin 457 result := trim(copy(ruleset, colonPos+1, valueLength)); 458 end else 459 result := ''; 460 end; 1079 begin 1080 result:= GetStyle(AName,''); 1081 end; 461 1082 462 1083 function TSVGElement.GetTransform: string; … … 470 1091 end; 471 1092 1093 function TSVGElement.GetVerticalAttributeWithUnit(AName: string; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit; 1094 begin 1095 result := GetAttributeWithUnit(AName,ADefault); 1096 if result.value <> EmptySingle then 1097 begin 1098 if result.CSSUnit <> cuCustom then 1099 if units.DpiScaleY = 0 then 1100 result.value := 0 1101 else 1102 result.value /= Units.DpiScaleY; 1103 end; 1104 end; 1105 472 1106 function TSVGElement.GetVerticalAttributeWithUnit(AName: string): TFloatWithCSSUnit; 473 1107 begin 474 result := GetAttributeWithUnit(AName); 475 if result.CSSUnit <> cuCustom then 476 if units.DpiScaleY = 0 then 477 result.value := 0 478 else 479 result.value /= Units.DpiScaleY; 480 end; 1108 result := GetVerticalAttributeWithUnit(AName,FloatWithCSSUnit(0,cuCustom)); 1109 end; 481 1110 482 1111 function TSVGElement.GetDOMElement: TDOMElement; … … 484 1113 result := FDomElem; 485 1114 end; 1115 1116 function TSVGElement.GetID: string; 1117 begin 1118 result := Attribute['id']; 1119 end; 1120 1121 function TSVGElement.GetClassAt: string; 1122 begin 1123 result := Attribute['class']; 1124 end; 486 1125 487 1126 procedure TSVGElement.SetAttribute(AName: string; AValue: string); … … 514 1153 RemoveStyle('fill-opacity'); 515 1154 end; 1155 1156 procedure TSVGElement.SetFillRule(AValue: string); 1157 begin 1158 Attribute['fill-rule'] := AValue; 1159 RemoveStyle('fill-rule'); 1160 end; 516 1161 517 1162 procedure TSVGElement.SetHorizAttributeWithUnit(AName: string; … … 613 1258 end; 614 1259 1260 procedure TSVGElement.SetStrokeDashArray(AValue: string); 1261 begin 1262 Attribute['stroke-dasharray'] := AValue; 1263 end; 1264 1265 procedure TSVGElement.SetStrokeDashArrayF(AValue: ArrayOfFloat); 1266 var 1267 s: string; 1268 i: integer; 1269 begin 1270 s:= ''; 1271 for i := 0 to high(AValue) do 1272 begin 1273 if s <> '' then s += ' '; 1274 s += TCSSUnitConverter.formatValue(AValue[i])+' '; 1275 end; 1276 strokeDashArray := s; 1277 end; 1278 1279 procedure TSVGElement.SetStrokeDashOffset(AValue: TFloatWithCSSUnit); 1280 begin 1281 OrthoAttributeWithUnit['stroke-dashoffset'] := AValue; 1282 end; 1283 615 1284 procedure TSVGElement.SetStyle(AName: string; AValue: string); 616 1285 var … … 668 1337 SetHorizAttributeWithUnit(AName,AValue); 669 1338 end; 1339 1340 procedure TSVGElement.SetID(AValue: string); 1341 begin 1342 Attribute['id'] := AValue; 1343 end; 1344 1345 procedure TSVGElement.SetClassAt(AValue: string); 1346 begin 1347 Attribute['class'] := AValue; 1348 end; 670 1349 671 1350 procedure TSVGElement.Init(ADocument: TXMLDocument; ATag: string; … … 748 1427 end; 749 1428 1429 procedure TSVGElement.ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit); 1430 begin 1431 ACanvas2D.fillStyle(fillColor); 1432 1433 ACanvas2D.fillMode := TFillMode(fillMode); 1434 end; 1435 750 1436 procedure TSVGElement.ApplyStrokeStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit); 1437 var 1438 a: ArrayOfFloat; 1439 lw: single; 1440 i: Integer; 751 1441 begin 752 1442 ACanvas2d.strokeStyle(strokeColor); 753 ACanvas2d.lineWidth := Units.ConvertWidth(strokeWidth,AUnit).value; 1443 lw := Units.ConvertWidth(strokeWidth,AUnit).value; 1444 ACanvas2d.lineWidth := lw; 754 1445 ACanvas2d.lineCap := strokeLineCap; 755 1446 ACanvas2d.lineJoin := strokeLineJoin; 756 1447 ACanvas2d.miterLimit := strokeMiterLimit; 1448 1449 a:= strokeDashArrayF; 1450 if (Length(a) <> 0) and (lw > 0) then 1451 begin 1452 for i := 0 to high(a) do 1453 a[i] /= lw; 1454 ACanvas2d.lineStyle(a); 1455 end 1456 else 1457 ACanvas2d.lineStyle(psSolid); 1458 end; 1459 1460 procedure TSVGElement.Initialize; 1461 begin 1462 SetLength(styleAttributes,0); 1463 findStyleState := fssNotSearch; 1464 FDataParent := nil; 1465 FDataChildList := TSVGElementList.Create; 757 1466 end; 758 1467 759 1468 constructor TSVGElement.Create(ADocument: TXMLDocument; AElement: TDOMElement; 760 AUnits: TCSSUnitConverter); 761 begin 1469 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1470 begin 1471 FDataLink:= ADataLink; 1472 Initialize; 762 1473 Init(ADocument,AElement,AUnits); 763 1474 end; 764 1475 765 1476 constructor TSVGElement.Create(ADocument: TXMLDocument; 766 AUnits: TCSSUnitConverter); 767 begin 768 raise exception.Create('Cannot create a generic element'); 1477 AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); 1478 begin 1479 FDataLink:= ADataLink; 1480 Initialize; 1481 //raise exception.Create('Cannot create a generic element'); 1482 end; 1483 1484 destructor TSVGElement.Destroy; 1485 begin 1486 SetLength(styleAttributes,0); 1487 FreeAndNil(FDataChildList); 1488 inherited Destroy; 1489 end; 1490 1491 procedure TSVGElement.Recompute; 1492 begin 1493 769 1494 end; 770 1495 … … 809 1534 end; 810 1535 1536 function TSVGElement.HasAttribute(AName: string): boolean; 1537 begin 1538 result := FDomElem.hasAttribute(AName); 1539 end; 1540 1541 function TSVGElement.fillMode: TSVGFillMode; 1542 begin 1543 if fillRule = 'evenodd' then 1544 result := sfmEvenOdd 1545 else 1546 result := sfmNonZero; 1547 end; 1548 1549 function TSVGElement.DataChildList: TSVGElementList; 1550 begin 1551 result:= FDataChildList; 1552 end; 1553 1554 function TSVGElement.FindStyleElementInternal(const classStr: string; 1555 out attributesStr: string): integer; 1556 var 1557 i: integer; 1558 begin 1559 attributesStr:= ''; 1560 with FDataLink do 1561 for i:= 0 to StyleCount-1 do 1562 begin 1563 result:= (Styles[i] as TSVGStyle).Find(classStr); 1564 if result <> -1 then 1565 begin 1566 attributesStr:= (Styles[i] as TSVGStyle).Styles[result].attribute; 1567 Exit; 1568 end; 1569 end; 1570 result:= -1; 1571 end; 1572 1573 procedure TSVGElement.FindStyleElement; 1574 1575 procedure AddStyle(const s: string; const id: integer); 1576 var 1577 l: integer; 1578 begin 1579 findStyleState:= fssFind; 1580 l:= Length(styleAttributes); 1581 SetLength(styleAttributes,l+1); 1582 with styleAttributes[l] do 1583 begin 1584 attr:= s; 1585 pos:= id; 1586 end; 1587 end; 1588 1589 var 1590 fid: integer; 1591 tag,styleC,s: string; 1592 begin 1593 findStyleState:= fssNotFind; 1594 SetLength(styleAttributes,0); 1595 tag:= FDomElem.TagName; 1596 styleC:= classAt; 1597 (* 1598 if style element is: 1599 <style> 1600 circle.test{fill:red; fill-opacity: 0.8;} 1601 circle{fill:blue; fill-opacity: 0.4;} 1602 circle.style1{fill:yellow;} 1603 </style> 1604 and circle declare: 1605 <circle class = "style1" cx="160" cy="160" r="35" stroke="black" /> 1606 1607 styleAttributes[0] = 'fill:blue; fill-opacity: 0.4;' 1608 styleAttributes[1] = 'fill:yellow;' 1609 1610 fill-opacity for "style1" = 0.4 not default 1! 1611 *) 1612 1613 //Find as: "[tag]" example "circle" 1614 fid:= FindStyleElementInternal(tag,s); 1615 if fid <> -1 then 1616 AddStyle(s,fid); 1617 if styleC <> '' then 1618 begin 1619 //Find as: "[tag].[class]" example "circle.style1" 1620 fid:= FindStyleElementInternal(tag+'.'+styleC,s); 1621 if fid <> -1 then 1622 AddStyle(s,fid) 1623 else 1624 begin 1625 //Find as: ".[class]" example ".style1" 1626 fid:= FindStyleElementInternal('.'+styleC,s); 1627 if fid <> -1 then 1628 AddStyle(s,fid); 1629 end; 1630 end; 1631 end; 1632 811 1633 end. 812 1634
Note:
See TracChangeset
for help on using the changeset viewer.