| 1 | unit BGRASVGShapes;
|
|---|
| 2 |
|
|---|
| 3 | {$mode objfpc}{$H+}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, SysUtils, BGRAUnits, laz2_DOM, BGRAPath, BGRABitmapTypes,
|
|---|
| 9 | BGRACanvas2D, BGRASVGType;
|
|---|
| 10 |
|
|---|
| 11 | type
|
|---|
| 12 | TSVGGradient = class;
|
|---|
| 13 |
|
|---|
| 14 | { TSVGElementWithGradient }
|
|---|
| 15 |
|
|---|
| 16 | TSVGElementWithGradient = class(TSVGElement)
|
|---|
| 17 | private
|
|---|
| 18 | FGradientElement: TSVGGradient;
|
|---|
| 19 | FGradientElementDefined: boolean;
|
|---|
| 20 | FCanvasGradient: IBGRACanvasGradient2D;
|
|---|
| 21 | function EvaluatePercentage(fu: TFloatWithCSSUnit): single; { fu is a percentage of a number [0.0..1.0] }
|
|---|
| 22 | function GetGradientElement: TSVGGradient;
|
|---|
| 23 | procedure ResetGradient;
|
|---|
| 24 | function FindGradientElement: boolean;
|
|---|
| 25 | protected
|
|---|
| 26 | procedure Initialize; override;
|
|---|
| 27 | procedure AddStopElements(canvas: IBGRACanvasGradient2D);
|
|---|
| 28 | procedure CreateCanvasLinearGradient(ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
|
|---|
| 29 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
|---|
| 30 | procedure CreateCanvasRadialGradient(ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
|
|---|
| 31 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
|---|
| 32 | procedure ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 33 | public
|
|---|
| 34 | procedure InitializeGradient(ACanvas2d: TBGRACanvas2D;
|
|---|
| 35 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
|---|
| 36 | property GradientElement: TSVGGradient read GetGradientElement;
|
|---|
| 37 | end;
|
|---|
| 38 |
|
|---|
| 39 | { TSVGLine }
|
|---|
| 40 |
|
|---|
| 41 | TSVGLine = class(TSVGElement)
|
|---|
| 42 | private
|
|---|
| 43 | function GetX1: TFloatWithCSSUnit;
|
|---|
| 44 | function GetX2: TFloatWithCSSUnit;
|
|---|
| 45 | function GetY1: TFloatWithCSSUnit;
|
|---|
| 46 | function GetY2: TFloatWithCSSUnit;
|
|---|
| 47 | procedure SetX1(AValue: TFloatWithCSSUnit);
|
|---|
| 48 | procedure SetX2(AValue: TFloatWithCSSUnit);
|
|---|
| 49 | procedure SetY1(AValue: TFloatWithCSSUnit);
|
|---|
| 50 | procedure SetY2(AValue: TFloatWithCSSUnit);
|
|---|
| 51 | protected
|
|---|
| 52 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 53 | public
|
|---|
| 54 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 55 | property x1: TFloatWithCSSUnit read GetX1 write SetX1;
|
|---|
| 56 | property y1: TFloatWithCSSUnit read GetY1 write SetY1;
|
|---|
| 57 | property x2: TFloatWithCSSUnit read GetX2 write SetX2;
|
|---|
| 58 | property y2: TFloatWithCSSUnit read GetY2 write SetY2;
|
|---|
| 59 | end;
|
|---|
| 60 |
|
|---|
| 61 | { TSVGRectangle }
|
|---|
| 62 |
|
|---|
| 63 | TSVGRectangle = class(TSVGElementWithGradient)
|
|---|
| 64 | private
|
|---|
| 65 | function GetX: TFloatWithCSSUnit;
|
|---|
| 66 | function GetY: TFloatWithCSSUnit;
|
|---|
| 67 | function GetWidth: TFloatWithCSSUnit;
|
|---|
| 68 | function GetHeight: TFloatWithCSSUnit;
|
|---|
| 69 | function GetRX: TFloatWithCSSUnit;
|
|---|
| 70 | function GetRY: TFloatWithCSSUnit;
|
|---|
| 71 | procedure SetX(AValue: TFloatWithCSSUnit);
|
|---|
| 72 | procedure SetY(AValue: TFloatWithCSSUnit);
|
|---|
| 73 | procedure SetWidth(AValue: TFloatWithCSSUnit);
|
|---|
| 74 | procedure SetHeight(AValue: TFloatWithCSSUnit);
|
|---|
| 75 | procedure SetRX(AValue: TFloatWithCSSUnit);
|
|---|
| 76 | procedure SetRY(AValue: TFloatWithCSSUnit);
|
|---|
| 77 | protected
|
|---|
| 78 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 79 | public
|
|---|
| 80 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 81 | property x: TFloatWithCSSUnit read GetX write SetX;
|
|---|
| 82 | property y: TFloatWithCSSUnit read GetY write SetY;
|
|---|
| 83 | property width: TFloatWithCSSUnit read GetWidth write SetWidth;
|
|---|
| 84 | property height: TFloatWithCSSUnit read GetHeight write SetHeight;
|
|---|
| 85 | property rx: TFloatWithCSSUnit read GetRX write SetRX;
|
|---|
| 86 | property ry: TFloatWithCSSUnit read GetRY write SetRY;
|
|---|
| 87 | end;
|
|---|
| 88 |
|
|---|
| 89 | { TSVGCircle }
|
|---|
| 90 |
|
|---|
| 91 | TSVGCircle = class(TSVGElementWithGradient)
|
|---|
| 92 | private
|
|---|
| 93 | function GetCX: TFloatWithCSSUnit;
|
|---|
| 94 | function GetCY: TFloatWithCSSUnit;
|
|---|
| 95 | function GetR: TFloatWithCSSUnit;
|
|---|
| 96 | procedure SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 97 | procedure SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 98 | procedure SetR(AValue: TFloatWithCSSUnit);
|
|---|
| 99 | protected
|
|---|
| 100 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 101 | public
|
|---|
| 102 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 103 | property cx: TFloatWithCSSUnit read GetCX write SetCX;
|
|---|
| 104 | property cy: TFloatWithCSSUnit read GetCY write SetCY;
|
|---|
| 105 | property r: TFloatWithCSSUnit read GetR write SetR;
|
|---|
| 106 | end;
|
|---|
| 107 |
|
|---|
| 108 | { TSVGEllipse }
|
|---|
| 109 |
|
|---|
| 110 | TSVGEllipse = class(TSVGElementWithGradient)
|
|---|
| 111 | private
|
|---|
| 112 | function GetCX: TFloatWithCSSUnit;
|
|---|
| 113 | function GetCY: TFloatWithCSSUnit;
|
|---|
| 114 | function GetRX: TFloatWithCSSUnit;
|
|---|
| 115 | function GetRY: TFloatWithCSSUnit;
|
|---|
| 116 | procedure SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 117 | procedure SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 118 | procedure SetRX(AValue: TFloatWithCSSUnit);
|
|---|
| 119 | procedure SetRY(AValue: TFloatWithCSSUnit);
|
|---|
| 120 | protected
|
|---|
| 121 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 122 | public
|
|---|
| 123 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 124 | property cx: TFloatWithCSSUnit read GetCX write SetCX;
|
|---|
| 125 | property cy: TFloatWithCSSUnit read GetCY write SetCY;
|
|---|
| 126 | property rx: TFloatWithCSSUnit read GetRX write SetRX;
|
|---|
| 127 | property ry: TFloatWithCSSUnit read GetRY write SetRY;
|
|---|
| 128 | end;
|
|---|
| 129 |
|
|---|
| 130 | { TSVGPath }
|
|---|
| 131 |
|
|---|
| 132 | TSVGPath = class(TSVGElementWithGradient)
|
|---|
| 133 | private
|
|---|
| 134 | FPath: TBGRAPath;
|
|---|
| 135 | FBoundingBox: TRectF;
|
|---|
| 136 | FBoundingBoxComputed: boolean;
|
|---|
| 137 | function GetBoundingBoxF: TRectF;
|
|---|
| 138 | function GetPath: TBGRAPath;
|
|---|
| 139 | function GetPathLength: TFloatWithCSSUnit;
|
|---|
| 140 | function GetData: string;
|
|---|
| 141 | procedure SetPathLength(AValue: TFloatWithCSSUnit);
|
|---|
| 142 | procedure SetData(AValue: string);
|
|---|
| 143 | protected
|
|---|
| 144 | function GetDOMElement: TDOMElement; override;
|
|---|
| 145 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 146 | public
|
|---|
| 147 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 148 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 149 | destructor Destroy; override;
|
|---|
| 150 | property d: string read GetData write SetData;
|
|---|
| 151 | property path: TBGRAPath read GetPath;
|
|---|
| 152 | property pathLength: TFloatWithCSSUnit read GetPathLength write SetPathLength;
|
|---|
| 153 | property boundingBoxF: TRectF read GetBoundingBoxF;
|
|---|
| 154 | end;
|
|---|
| 155 |
|
|---|
| 156 | { TSVGPolypoints }
|
|---|
| 157 |
|
|---|
| 158 | TSVGPolypoints = class(TSVGElementWithGradient)
|
|---|
| 159 | private
|
|---|
| 160 | FBoundingBox: TRectF;
|
|---|
| 161 | FBoundingBoxComputed: boolean;
|
|---|
| 162 | function GetBoundingBoxF: TRectF;
|
|---|
| 163 | function GetClosed: boolean;
|
|---|
| 164 | function GetPoints: string;
|
|---|
| 165 | function GetPointsF: ArrayOfTPointF;
|
|---|
| 166 | procedure SetPoints(AValue: string);
|
|---|
| 167 | procedure SetPointsF(AValue: ArrayOfTPointF);
|
|---|
| 168 | procedure ComputeBoundingBox(APoints: ArrayOfTPointF);
|
|---|
| 169 | protected
|
|---|
| 170 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 171 | public
|
|---|
| 172 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink); overload;
|
|---|
| 173 | destructor Destroy; override;
|
|---|
| 174 | property points: string read GetPoints write SetPoints;
|
|---|
| 175 | property pointsF: ArrayOfTPointF read GetPointsF write SetPointsF;
|
|---|
| 176 | property closed: boolean read GetClosed;
|
|---|
| 177 | property boundingBoxF: TRectF read GetBoundingBoxF;
|
|---|
| 178 | end;
|
|---|
| 179 |
|
|---|
| 180 | { TSVGText }
|
|---|
| 181 |
|
|---|
| 182 | TSVGText = class(TSVGElementWithGradient)
|
|---|
| 183 | private
|
|---|
| 184 | function GetFontBold: boolean;
|
|---|
| 185 | function GetFontFamily: string;
|
|---|
| 186 | function GetFontItalic: boolean;
|
|---|
| 187 | function GetFontSize: TFloatWithCSSUnit;
|
|---|
| 188 | function GetFontStyle: string;
|
|---|
| 189 | function GetFontWeight: string;
|
|---|
| 190 | function GetSimpleText: string;
|
|---|
| 191 | function GetTextDecoration: string;
|
|---|
| 192 | function GetX: TFloatWithCSSUnit;
|
|---|
| 193 | function GetY: TFloatWithCSSUnit;
|
|---|
| 194 | procedure SetFontBold(AValue: boolean);
|
|---|
| 195 | procedure SetFontFamily(AValue: string);
|
|---|
| 196 | procedure SetFontItalic(AValue: boolean);
|
|---|
| 197 | procedure SetFontSize(AValue: TFloatWithCSSUnit);
|
|---|
| 198 | procedure SetFontStyle(AValue: string);
|
|---|
| 199 | procedure SetFontWeight(AValue: string);
|
|---|
| 200 | procedure SetSimpleText(AValue: string);
|
|---|
| 201 | procedure SetTextDecoration(AValue: string);
|
|---|
| 202 | procedure SetX(AValue: TFloatWithCSSUnit);
|
|---|
| 203 | procedure SetY(AValue: TFloatWithCSSUnit);
|
|---|
| 204 | protected
|
|---|
| 205 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 206 | public
|
|---|
| 207 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 208 | property x: TFloatWithCSSUnit read GetX write SetX;
|
|---|
| 209 | property y: TFloatWithCSSUnit read GetY write SetY;
|
|---|
| 210 | property SimpleText: string read GetSimpleText write SetSimpleText;
|
|---|
| 211 | property fontSize: TFloatWithCSSUnit read GetFontSize write SetFontSize;
|
|---|
| 212 | property fontFamily: string read GetFontFamily write SetFontFamily;
|
|---|
| 213 | property fontWeight: string read GetFontWeight write SetFontWeight;
|
|---|
| 214 | property fontStyle: string read GetFontStyle write SetFontStyle;
|
|---|
| 215 | property textDecoration: string read GetTextDecoration write SetTextDecoration;
|
|---|
| 216 | property fontBold: boolean read GetFontBold write SetFontBold;
|
|---|
| 217 | property fontItalic: boolean read GetFontItalic write SetFontItalic;
|
|---|
| 218 | end;
|
|---|
| 219 |
|
|---|
| 220 | TSVGContent = class;
|
|---|
| 221 |
|
|---|
| 222 | TConvMethod = (cmNone,cmHoriz,cmVertical,cmOrtho);
|
|---|
| 223 |
|
|---|
| 224 | { TSVGGradient }
|
|---|
| 225 |
|
|---|
| 226 | TSVGGradient = class(TSVGElement)
|
|---|
| 227 | private
|
|---|
| 228 | FContent: TSVGContent;
|
|---|
| 229 | function GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
|
|---|
| 230 | function GetGradientTransform: string;
|
|---|
| 231 | function GetGradientUnits: string;
|
|---|
| 232 | function GetHRef: string;
|
|---|
| 233 | function GetUseObjectBoundingBox: boolean;
|
|---|
| 234 | procedure SetGradientTransform(AValue: string);
|
|---|
| 235 | procedure SetGradientUnits(AValue: string);
|
|---|
| 236 | procedure SetHRef(AValue: string);
|
|---|
| 237 | function HRefToGradientID(const AValue: string): string;
|
|---|
| 238 | function FindGradientRef(const AGradientID: string): integer;
|
|---|
| 239 | protected
|
|---|
| 240 | InheritedGradients: TSVGElementList;//(for HRef)
|
|---|
| 241 | procedure Initialize; override;
|
|---|
| 242 | function GetInheritedAttribute(AValue: string;
|
|---|
| 243 | AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
|
|---|
| 244 | public
|
|---|
| 245 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 246 | ADataLink: TSVGDataLink); override;
|
|---|
| 247 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 248 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 249 | destructor Destroy; override;
|
|---|
| 250 | procedure Recompute; override;
|
|---|
| 251 | procedure ScanInheritedGradients(const forceScan: boolean = false);
|
|---|
| 252 | property Content: TSVGContent read FContent;
|
|---|
| 253 | property hRef: string read GetHRef write SetHRef;
|
|---|
| 254 | property gradientUnits: string read GetGradientUnits write SetGradientUnits;
|
|---|
| 255 | property gradientTransform: string read GetGradientTransform write SetGradientTransform;
|
|---|
| 256 | property useObjectBoundingBox: boolean read GetUseObjectBoundingBox;
|
|---|
| 257 | property gradientMatrix[AUnit: TCSSUnit]: TAffineMatrix read GetGradientMatrix;
|
|---|
| 258 | end;
|
|---|
| 259 |
|
|---|
| 260 | { TSVGGradientLinear }
|
|---|
| 261 |
|
|---|
| 262 | TSVGLinearGradient = class(TSVGGradient)
|
|---|
| 263 | private
|
|---|
| 264 | function GetX1: TFloatWithCSSUnit;
|
|---|
| 265 | function GetX2: TFloatWithCSSUnit;
|
|---|
| 266 | function GetY1: TFloatWithCSSUnit;
|
|---|
| 267 | function GetY2: TFloatWithCSSUnit;
|
|---|
| 268 | procedure SetX1(AValue: TFloatWithCSSUnit);
|
|---|
| 269 | procedure SetX2(AValue: TFloatWithCSSUnit);
|
|---|
| 270 | procedure SetY1(AValue: TFloatWithCSSUnit);
|
|---|
| 271 | procedure SetY2(AValue: TFloatWithCSSUnit);
|
|---|
| 272 | public
|
|---|
| 273 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 274 | ADataLink: TSVGDataLink); override;
|
|---|
| 275 | property x1: TFloatWithCSSUnit read GetX1 write SetX1;
|
|---|
| 276 | property y1: TFloatWithCSSUnit read GetY1 write SetY1;
|
|---|
| 277 | property x2: TFloatWithCSSUnit read GetX2 write SetX2;
|
|---|
| 278 | property y2: TFloatWithCSSUnit read GetY2 write SetY2;
|
|---|
| 279 | end;
|
|---|
| 280 |
|
|---|
| 281 | { TSVGRadialGradient }
|
|---|
| 282 |
|
|---|
| 283 | TSVGRadialGradient = class(TSVGGradient)
|
|---|
| 284 | private
|
|---|
| 285 | function GetCX: TFloatWithCSSUnit;
|
|---|
| 286 | function GetCY: TFloatWithCSSUnit;
|
|---|
| 287 | function GetR: TFloatWithCSSUnit;
|
|---|
| 288 | function GetFX: TFloatWithCSSUnit;
|
|---|
| 289 | function GetFY: TFloatWithCSSUnit;
|
|---|
| 290 | function GetFR: TFloatWithCSSUnit;
|
|---|
| 291 | procedure SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 292 | procedure SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 293 | procedure SetR(AValue: TFloatWithCSSUnit);
|
|---|
| 294 | procedure SetFX(AValue: TFloatWithCSSUnit);
|
|---|
| 295 | procedure SetFY(AValue: TFloatWithCSSUnit);
|
|---|
| 296 | procedure SetFR(AValue: TFloatWithCSSUnit);
|
|---|
| 297 | public
|
|---|
| 298 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 299 | ADataLink: TSVGDataLink); override;
|
|---|
| 300 | property cx: TFloatWithCSSUnit read GetCX write SetCX;
|
|---|
| 301 | property cy: TFloatWithCSSUnit read GetCY write SetCY;
|
|---|
| 302 | property r: TFloatWithCSSUnit read GetR write SetR;
|
|---|
| 303 | property fx: TFloatWithCSSUnit read GetFX write SetFX;
|
|---|
| 304 | property fy: TFloatWithCSSUnit read GetFY write SetFY;
|
|---|
| 305 | property fr: TFloatWithCSSUnit read GetFR write SetFR;
|
|---|
| 306 | end;
|
|---|
| 307 |
|
|---|
| 308 | { TSVGStopGradient }
|
|---|
| 309 |
|
|---|
| 310 | TSVGStopGradient = class(TSVGElement)
|
|---|
| 311 | private
|
|---|
| 312 | function GetOffset: TFloatWithCSSUnit;
|
|---|
| 313 | procedure SetOffset(AValue: TFloatWithCSSUnit);
|
|---|
| 314 | public
|
|---|
| 315 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 316 | ADataLink: TSVGDataLink); override;
|
|---|
| 317 | property Offset: TFloatWithCSSUnit read GetOffset write SetOffset;
|
|---|
| 318 | end;
|
|---|
| 319 |
|
|---|
| 320 | { TSVGDefine }
|
|---|
| 321 |
|
|---|
| 322 | TSVGDefine = class(TSVGElement)
|
|---|
| 323 | protected
|
|---|
| 324 | FContent: TSVGContent;
|
|---|
| 325 | public
|
|---|
| 326 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 327 | ADataLink: TSVGDataLink); override;
|
|---|
| 328 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 329 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 330 | destructor Destroy; override;
|
|---|
| 331 | procedure Recompute; override;
|
|---|
| 332 | property Content: TSVGContent read FContent;
|
|---|
| 333 | end;
|
|---|
| 334 |
|
|---|
| 335 | { TSVGGroup }
|
|---|
| 336 |
|
|---|
| 337 | TSVGGroup = class(TSVGElement)
|
|---|
| 338 | protected
|
|---|
| 339 | FContent: TSVGContent;
|
|---|
| 340 | procedure InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); override;
|
|---|
| 341 | public
|
|---|
| 342 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 343 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 344 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); override;
|
|---|
| 345 | destructor Destroy; override;
|
|---|
| 346 | procedure Recompute; override;
|
|---|
| 347 | property Content: TSVGContent read FContent;
|
|---|
| 348 | end;
|
|---|
| 349 |
|
|---|
| 350 | { TSVGStyle }
|
|---|
| 351 |
|
|---|
| 352 | TSVGStyleItem = record
|
|---|
| 353 | name,
|
|---|
| 354 | attribute: string;
|
|---|
| 355 | end;
|
|---|
| 356 | ArrayOfTSVGStyleItem = array of TSVGStyleItem;
|
|---|
| 357 |
|
|---|
| 358 | TSVGStyle = class(TSVGElement)
|
|---|
| 359 | private
|
|---|
| 360 | FStyles: ArrayOfTSVGStyleItem;
|
|---|
| 361 | procedure Parse(const s: String);
|
|---|
| 362 | function IsValidID(const sid: integer): boolean;
|
|---|
| 363 | function GetStyle(const sid: integer): TSVGStyleItem;
|
|---|
| 364 | procedure SetStyle(const sid: integer; sr: TSVGStyleItem);
|
|---|
| 365 | function Find(sr: TSVGStyleItem): integer; overload;
|
|---|
| 366 | protected
|
|---|
| 367 | procedure Initialize; override;
|
|---|
| 368 | public
|
|---|
| 369 | constructor Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; override;
|
|---|
| 370 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 371 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink); overload; override;
|
|---|
| 372 | destructor Destroy; override;
|
|---|
| 373 | function Count: Integer;
|
|---|
| 374 | function Find(const AName: string): integer; overload;
|
|---|
| 375 | function Add(sr: TSVGStyleItem): integer;
|
|---|
| 376 | procedure Remove(sr: TSVGStyleItem);
|
|---|
| 377 | procedure Clear;
|
|---|
| 378 | procedure ReParse;
|
|---|
| 379 | property Styles[sid: integer]: TSVGStyleItem read GetStyle write SetStyle;
|
|---|
| 380 | end;
|
|---|
| 381 |
|
|---|
| 382 | { TSVGContent }
|
|---|
| 383 |
|
|---|
| 384 | TSVGContent = class
|
|---|
| 385 | protected
|
|---|
| 386 | FDataLink: TSVGDataLink;
|
|---|
| 387 | FDomElem: TDOMElement;
|
|---|
| 388 | FDoc: TXMLDocument;
|
|---|
| 389 | FElements: TFPList;
|
|---|
| 390 | FUnits: TCSSUnitConverter;
|
|---|
| 391 | procedure AppendElement(AElement: TSVGElement);
|
|---|
| 392 | procedure InsertElementBefore(AElement: TSVGElement; ASuccessor: TSVGElement);
|
|---|
| 393 | function GetElement(AIndex: integer): TSVGElement;
|
|---|
| 394 | function GetElementCount: integer;
|
|---|
| 395 | function GetUnits: TCSSUnitConverter;
|
|---|
| 396 | public
|
|---|
| 397 | constructor Create(ADocument: TXMLDocument; AElement: TDOMElement; AUnits: TCSSUnitConverter;
|
|---|
| 398 | ADataLink: TSVGDataLink; ADataParent: TSVGElement);
|
|---|
| 399 | destructor Destroy; override;
|
|---|
| 400 | procedure Recompute;
|
|---|
| 401 | procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; AUnit: TCSSUnit); overload;
|
|---|
| 402 | procedure Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit); overload;
|
|---|
| 403 | function AppendLine(x1,y1,x2,y2: single; AUnit: TCSSUnit = cuCustom): TSVGLine; overload;
|
|---|
| 404 | function AppendLine(p1,p2: TPointF; AUnit: TCSSUnit = cuCustom): TSVGLine; overload;
|
|---|
| 405 | function AppendCircle(cx,cy,r: single; AUnit: TCSSUnit = cuCustom): TSVGCircle; overload;
|
|---|
| 406 | function AppendCircle(c: TPointF; r: single; AUnit: TCSSUnit = cuCustom): TSVGCircle; overload;
|
|---|
| 407 | function AppendEllipse(cx,cy,rx,ry: single; AUnit: TCSSUnit = cuCustom): TSVGEllipse; overload;
|
|---|
| 408 | function AppendEllipse(c,r: TPointF; AUnit: TCSSUnit = cuCustom): TSVGEllipse; overload;
|
|---|
| 409 | function AppendPath(data: string; AUnit: TCSSUnit = cuCustom): TSVGPath; overload;
|
|---|
| 410 | function AppendPath(path: TBGRAPath; AUnit: TCSSUnit = cuCustom): TSVGPath; overload;
|
|---|
| 411 | function AppendPolygon(const points: array of single; AUnit: TCSSUnit = cuCustom): TSVGPolypoints; overload;
|
|---|
| 412 | function AppendPolygon(const points: array of TPointF; AUnit: TCSSUnit = cuCustom): TSVGPolypoints; overload;
|
|---|
| 413 | function AppendRect(x,y,width,height: single; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
|---|
| 414 | function AppendRect(origin,size: TPointF; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
|---|
| 415 | function AppendText(x,y: single; AText: string; AUnit: TCSSUnit = cuCustom): TSVGText; overload;
|
|---|
| 416 | function AppendText(origin: TPointF; AText: string; AUnit: TCSSUnit = cuCustom): TSVGText; overload;
|
|---|
| 417 | function AppendRoundRect(x,y,width,height,rx,ry: single; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
|---|
| 418 | function AppendRoundRect(origin,size,radius: TPointF; AUnit: TCSSUnit = cuCustom): TSVGRectangle; overload;
|
|---|
| 419 | property ElementCount: integer read GetElementCount;
|
|---|
| 420 | property Element[AIndex: integer]: TSVGElement read GetElement;
|
|---|
| 421 | property Units: TCSSUnitConverter read GetUnits;
|
|---|
| 422 | end;
|
|---|
| 423 |
|
|---|
| 424 | function GetSVGFactory(ATagName: string): TSVGFactory;
|
|---|
| 425 | function CreateSVGElementFromNode(ADocument: TXMLDocument;
|
|---|
| 426 | AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
|
|---|
| 427 |
|
|---|
| 428 | implementation
|
|---|
| 429 |
|
|---|
| 430 | uses BGRATransform, BGRAGraphics;
|
|---|
| 431 |
|
|---|
| 432 | function GetSVGFactory(ATagName: string): TSVGFactory;
|
|---|
| 433 | var tag: string;
|
|---|
| 434 | begin
|
|---|
| 435 | tag := LowerCase(ATagName);
|
|---|
| 436 | if tag='line' then
|
|---|
| 437 | result := TSVGLine else
|
|---|
| 438 | if tag='rect' then
|
|---|
| 439 | result := TSVGRectangle else
|
|---|
| 440 | if tag='circle' then
|
|---|
| 441 | result := TSVGCircle else
|
|---|
| 442 | if tag='ellipse' then
|
|---|
| 443 | result := TSVGEllipse else
|
|---|
| 444 | if tag='path' then
|
|---|
| 445 | result := TSVGPath else
|
|---|
| 446 | if (tag='polygon') or (tag='polyline') then
|
|---|
| 447 | result := TSVGPolypoints else
|
|---|
| 448 | if tag='text' then
|
|---|
| 449 | result := TSVGText else
|
|---|
| 450 | if tag='lineargradient' then
|
|---|
| 451 | result := TSVGLinearGradient else
|
|---|
| 452 | if tag='radialgradient' then
|
|---|
| 453 | result := TSVGRadialGradient else
|
|---|
| 454 | if tag='stop' then
|
|---|
| 455 | result := TSVGStopGradient else
|
|---|
| 456 | if tag='defs' then
|
|---|
| 457 | result := TSVGDefine else
|
|---|
| 458 | if tag='g' then
|
|---|
| 459 | result := TSVGGroup else
|
|---|
| 460 | if tag='style' then
|
|---|
| 461 | result := TSVGStyle else
|
|---|
| 462 | result := TSVGElement;
|
|---|
| 463 | end;
|
|---|
| 464 |
|
|---|
| 465 | function CreateSVGElementFromNode(ADocument: TXMLDocument;
|
|---|
| 466 | AElement: TDOMElement; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement): TSVGElement;
|
|---|
| 467 | var
|
|---|
| 468 | factory: TSVGFactory;
|
|---|
| 469 | begin
|
|---|
| 470 | factory := GetSVGFactory(AElement.TagName);
|
|---|
| 471 | result := factory.Create(ADocument,AElement,AUnits,ADataLink);
|
|---|
| 472 |
|
|---|
| 473 | ADataLink.Link(result,ADataParent);
|
|---|
| 474 | end;
|
|---|
| 475 |
|
|---|
| 476 | { TSVGElementWithGradient }
|
|---|
| 477 |
|
|---|
| 478 | procedure TSVGElementWithGradient.Initialize;
|
|---|
| 479 | begin
|
|---|
| 480 | inherited Initialize;
|
|---|
| 481 | ResetGradient;
|
|---|
| 482 | end;
|
|---|
| 483 |
|
|---|
| 484 | procedure TSVGElementWithGradient.ResetGradient;
|
|---|
| 485 | begin
|
|---|
| 486 | FGradientElementDefined := false;
|
|---|
| 487 | FGradientElement := nil;
|
|---|
| 488 | FCanvasGradient := nil;
|
|---|
| 489 | end;
|
|---|
| 490 |
|
|---|
| 491 | function TSVGElementWithGradient.FindGradientElement: boolean;
|
|---|
| 492 | var
|
|---|
| 493 | i: integer;
|
|---|
| 494 | s: string;
|
|---|
| 495 | begin
|
|---|
| 496 | Result:= false;
|
|---|
| 497 | s:= fill;
|
|---|
| 498 | if s <> '' then
|
|---|
| 499 | if Pos('url(#',s) = 1 then
|
|---|
| 500 | begin
|
|---|
| 501 | s:= System.Copy(s,6,Length(s)-6);
|
|---|
| 502 | with FDataLink do
|
|---|
| 503 | for i:= GradientCount-1 downto 0 do
|
|---|
| 504 | if (Gradients[i] as TSVGGradient).ID = s then
|
|---|
| 505 | begin
|
|---|
| 506 | FGradientElement:= TSVGGradient(Gradients[i]);
|
|---|
| 507 | Result:= true;
|
|---|
| 508 | Exit;
|
|---|
| 509 | end;
|
|---|
| 510 | end;
|
|---|
| 511 | end;
|
|---|
| 512 |
|
|---|
| 513 | function TSVGElementWithGradient.EvaluatePercentage(fu: TFloatWithCSSUnit): single;
|
|---|
| 514 | begin
|
|---|
| 515 | Result:= fu.value;
|
|---|
| 516 | if fu.CSSUnit <> cuPercent then
|
|---|
| 517 | begin
|
|---|
| 518 | if Result < 0 then
|
|---|
| 519 | Result:= 0
|
|---|
| 520 | else if Result > 1 then
|
|---|
| 521 | Result:= 1;
|
|---|
| 522 | Result:= Result * 100;
|
|---|
| 523 | end;
|
|---|
| 524 | end;
|
|---|
| 525 |
|
|---|
| 526 | function TSVGElementWithGradient.GetGradientElement: TSVGGradient;
|
|---|
| 527 | begin
|
|---|
| 528 | if not FGradientElementDefined then
|
|---|
| 529 | begin
|
|---|
| 530 | FindGradientElement;
|
|---|
| 531 | FGradientElementDefined:= true;
|
|---|
| 532 | if FGradientElement <> nil then
|
|---|
| 533 | FGradientElement.ScanInheritedGradients;
|
|---|
| 534 | end;
|
|---|
| 535 | result := FGradientElement;
|
|---|
| 536 | end;
|
|---|
| 537 |
|
|---|
| 538 | procedure TSVGElementWithGradient.AddStopElements(canvas: IBGRACanvasGradient2D);
|
|---|
| 539 |
|
|---|
| 540 | function AddStopElementFrom(el: TSVGElement): integer;
|
|---|
| 541 | var
|
|---|
| 542 | i: integer;
|
|---|
| 543 | col: TBGRAPixel;
|
|---|
| 544 | begin
|
|---|
| 545 | result:= 0;
|
|---|
| 546 | with el.DataChildList do
|
|---|
| 547 | for i:= 0 to Count-1 do
|
|---|
| 548 | if Items[i] is TSVGStopGradient then
|
|---|
| 549 | with (Items[i] as TSVGStopGradient) do
|
|---|
| 550 | begin
|
|---|
| 551 | col:= StrToBGRA( AttributeOrStyleDef['stop-color','black'] );
|
|---|
| 552 | col.alpha:= Round( Units.parseValue(AttributeOrStyleDef['stop-opacity','1'],1) * col.alpha );
|
|---|
| 553 | canvas.addColorStop(EvaluatePercentage(offset)/100, col);
|
|---|
| 554 | Inc(result);
|
|---|
| 555 | end;
|
|---|
| 556 | end;
|
|---|
| 557 |
|
|---|
| 558 | var
|
|---|
| 559 | i: integer;
|
|---|
| 560 | begin
|
|---|
| 561 | if not Assigned(GradientElement) then exit;
|
|---|
| 562 | with GradientElement.InheritedGradients do
|
|---|
| 563 | for i:= 0 to Count-1 do
|
|---|
| 564 | AddStopElementFrom(Items[i]);
|
|---|
| 565 | end;
|
|---|
| 566 |
|
|---|
| 567 | procedure TSVGElementWithGradient.CreateCanvasLinearGradient(
|
|---|
| 568 | ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient;
|
|---|
| 569 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
|---|
| 570 | var p1,p2: TPointF;
|
|---|
| 571 | g: TSVGLinearGradient;
|
|---|
| 572 | m: TAffineMatrix;
|
|---|
| 573 | begin
|
|---|
| 574 | g := ASVGGradient as TSVGLinearGradient;
|
|---|
| 575 | if g.useObjectBoundingBox then
|
|---|
| 576 | begin
|
|---|
| 577 | p1.x:= EvaluatePercentage(g.x1)/100;
|
|---|
| 578 | p1.y:= EvaluatePercentage(g.y1)/100;
|
|---|
| 579 | p2.x:= EvaluatePercentage(g.x2)/100;
|
|---|
| 580 | p2.y:= EvaluatePercentage(g.y2)/100;
|
|---|
| 581 | m := ACanvas2d.matrix;
|
|---|
| 582 | ACanvas2d.translate(origin.x,origin.y);
|
|---|
| 583 | ACanvas2d.scale(w,h);
|
|---|
| 584 | ACanvas2d.transform(g.gradientMatrix[cuCustom]);
|
|---|
| 585 | FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
|
|---|
| 586 | ACanvas2d.matrix := m;
|
|---|
| 587 | end else
|
|---|
| 588 | begin
|
|---|
| 589 | p1.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
|
|---|
| 590 | p1.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
|
|---|
| 591 | p2.x:= Units.ConvertWidth(g.x1,AUnit,w).value;
|
|---|
| 592 | p2.y:= Units.ConvertHeight(g.y1,AUnit,h).value;
|
|---|
| 593 | m := ACanvas2d.matrix;
|
|---|
| 594 | ACanvas2d.transform(g.gradientMatrix[AUnit]);
|
|---|
| 595 | FCanvasGradient:= ACanvas2d.createLinearGradient(p1,p2);
|
|---|
| 596 | ACanvas2d.matrix := m;
|
|---|
| 597 | end;
|
|---|
| 598 |
|
|---|
| 599 | AddStopElements(FCanvasGradient);
|
|---|
| 600 | end;
|
|---|
| 601 |
|
|---|
| 602 | procedure TSVGElementWithGradient.CreateCanvasRadialGradient(
|
|---|
| 603 | ACanvas2d: TBGRACanvas2D; ASVGGradient: TSVGGradient; const origin: TPointF;
|
|---|
| 604 | const w, h: single; AUnit: TCSSUnit);
|
|---|
| 605 | var c,f: TPointF;
|
|---|
| 606 | r,fr: single;
|
|---|
| 607 | g: TSVGRadialGradient;
|
|---|
| 608 | m: TAffineMatrix;
|
|---|
| 609 |
|
|---|
| 610 | procedure CheckFocalAndCreate(c: TPointF; r: single; f: TPointF; fr: single);
|
|---|
| 611 | var u: TPointF;
|
|---|
| 612 | d: single;
|
|---|
| 613 | begin
|
|---|
| 614 | u := f-c;
|
|---|
| 615 | d := VectLen(u);
|
|---|
| 616 | if d >= r then
|
|---|
| 617 | begin
|
|---|
| 618 | u *= (r/d)*0.99999;
|
|---|
| 619 | f := c+u;
|
|---|
| 620 | end;
|
|---|
| 621 | FCanvasGradient:= ACanvas2d.createRadialGradient(c,r,f,fr,true);
|
|---|
| 622 | AddStopElements(FCanvasGradient);
|
|---|
| 623 | end;
|
|---|
| 624 |
|
|---|
| 625 | begin
|
|---|
| 626 | g := ASVGGradient as TSVGRadialGradient;
|
|---|
| 627 | if g.useObjectBoundingBox then
|
|---|
| 628 | begin
|
|---|
| 629 | c.x:= EvaluatePercentage(g.cx)/100;
|
|---|
| 630 | c.y:= EvaluatePercentage(g.cy)/100;
|
|---|
| 631 | r:= abs(EvaluatePercentage(g.r))/100;
|
|---|
| 632 | f.x:= EvaluatePercentage(g.fx)/100;
|
|---|
| 633 | f.y:= EvaluatePercentage(g.fy)/100;
|
|---|
| 634 | fr:= abs(EvaluatePercentage(g.fr))/100;
|
|---|
| 635 |
|
|---|
| 636 | m := ACanvas2d.matrix;
|
|---|
| 637 | ACanvas2d.translate(origin.x,origin.y);
|
|---|
| 638 | ACanvas2d.scale(w,h);
|
|---|
| 639 | ACanvas2d.transform(g.gradientMatrix[cuCustom]);
|
|---|
| 640 | CheckFocalAndCreate(c,r,f,fr);
|
|---|
| 641 | ACanvas2d.matrix := m;
|
|---|
| 642 | end else
|
|---|
| 643 | begin
|
|---|
| 644 | c.x:= Units.ConvertWidth(g.cx,AUnit,w).value;
|
|---|
| 645 | c.y:= Units.ConvertHeight(g.cy,AUnit,h).value;
|
|---|
| 646 | r:= abs(Units.ConvertWidth(g.r,AUnit,w).value);
|
|---|
| 647 | f.x:= Units.ConvertWidth(g.fx,AUnit,w).value;
|
|---|
| 648 | f.y:= Units.ConvertHeight(g.fy,AUnit,h).value;
|
|---|
| 649 | fr:= abs(Units.ConvertWidth(g.fr,AUnit,w).value);
|
|---|
| 650 |
|
|---|
| 651 | m := ACanvas2d.matrix;
|
|---|
| 652 | ACanvas2d.transform(g.gradientMatrix[AUnit]);
|
|---|
| 653 | CheckFocalAndCreate(c,r,f,fr);
|
|---|
| 654 | ACanvas2d.matrix := m;
|
|---|
| 655 | end;
|
|---|
| 656 | end;
|
|---|
| 657 |
|
|---|
| 658 | procedure TSVGElementWithGradient.InitializeGradient(ACanvas2d: TBGRACanvas2D;
|
|---|
| 659 | const origin: TPointF; const w,h: single; AUnit: TCSSUnit);
|
|---|
| 660 | begin
|
|---|
| 661 | if GradientElement <> nil then
|
|---|
| 662 | begin
|
|---|
| 663 | if GradientElement is TSVGLinearGradient then
|
|---|
| 664 | CreateCanvasLinearGradient(ACanvas2d, GradientElement, origin, w,h, AUnit)
|
|---|
| 665 | else
|
|---|
| 666 | if GradientElement is TSVGRadialGradient then
|
|---|
| 667 | CreateCanvasRadialGradient(ACanvas2d, GradientElement, origin, w,h, AUnit);
|
|---|
| 668 | end;
|
|---|
| 669 | end;
|
|---|
| 670 |
|
|---|
| 671 | procedure TSVGElementWithGradient.ApplyFillStyle(ACanvas2D: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 672 | begin
|
|---|
| 673 | if FCanvasGradient = nil then
|
|---|
| 674 | inherited ApplyFillStyle(ACanvas2D,AUnit)
|
|---|
| 675 | else
|
|---|
| 676 | begin
|
|---|
| 677 | ACanvas2D.fillStyle(FCanvasGradient);
|
|---|
| 678 | ACanvas2D.fillMode:= TFillMode(fillMode);
|
|---|
| 679 | end;
|
|---|
| 680 | end;
|
|---|
| 681 |
|
|---|
| 682 | { TSVGText }
|
|---|
| 683 |
|
|---|
| 684 | function TSVGText.GetFontBold: boolean;
|
|---|
| 685 | var valueText: string;
|
|---|
| 686 | begin
|
|---|
| 687 | valueText := trim(fontWeight);
|
|---|
| 688 | result := (valueText = 'bold') or (valueText = 'bolder') or
|
|---|
| 689 | (valueText = '600') or (valueText = '700') or (valueText = '800') or
|
|---|
| 690 | (valueText = '900');
|
|---|
| 691 | end;
|
|---|
| 692 |
|
|---|
| 693 | function TSVGText.GetFontFamily: string;
|
|---|
| 694 | begin
|
|---|
| 695 | result := AttributeOrStyleDef['font-family','Arial'];
|
|---|
| 696 | end;
|
|---|
| 697 |
|
|---|
| 698 | function TSVGText.GetFontItalic: boolean;
|
|---|
| 699 | var valueText: string;
|
|---|
| 700 | begin
|
|---|
| 701 | valueText := trim(fontStyle);
|
|---|
| 702 | result := (valueText = 'oblique') or (valueText = 'italic');
|
|---|
| 703 | end;
|
|---|
| 704 |
|
|---|
| 705 | function TSVGText.GetFontSize: TFloatWithCSSUnit;
|
|---|
| 706 | begin
|
|---|
| 707 | result:= VerticalAttributeOrStyleWithUnit['font-size',FloatWithCSSUnit(12,cuPoint)];
|
|---|
| 708 | end;
|
|---|
| 709 |
|
|---|
| 710 | function TSVGText.GetFontStyle: string;
|
|---|
| 711 | begin
|
|---|
| 712 | result := AttributeOrStyleDef['font-style','normal'];
|
|---|
| 713 | end;
|
|---|
| 714 |
|
|---|
| 715 | function TSVGText.GetFontWeight: string;
|
|---|
| 716 | begin
|
|---|
| 717 | result := AttributeOrStyleDef['font-weight','normal'];
|
|---|
| 718 | end;
|
|---|
| 719 |
|
|---|
| 720 | function TSVGText.GetSimpleText: string;
|
|---|
| 721 | begin
|
|---|
| 722 | result := FDomElem.TextContent;
|
|---|
| 723 | end;
|
|---|
| 724 |
|
|---|
| 725 | function TSVGText.GetTextDecoration: string;
|
|---|
| 726 | begin
|
|---|
| 727 | result := AttributeOrStyleDef['text-decoration','none'];
|
|---|
| 728 | end;
|
|---|
| 729 |
|
|---|
| 730 | function TSVGText.GetX: TFloatWithCSSUnit;
|
|---|
| 731 | begin
|
|---|
| 732 | result := HorizAttributeWithUnit['x'];
|
|---|
| 733 | end;
|
|---|
| 734 |
|
|---|
| 735 | function TSVGText.GetY: TFloatWithCSSUnit;
|
|---|
| 736 | begin
|
|---|
| 737 | result := VerticalAttributeWithUnit['y'];
|
|---|
| 738 | end;
|
|---|
| 739 |
|
|---|
| 740 | procedure TSVGText.SetFontBold(AValue: boolean);
|
|---|
| 741 | begin
|
|---|
| 742 | if AValue then fontWeight:= 'bold' else fontWeight:= 'normal';
|
|---|
| 743 | end;
|
|---|
| 744 |
|
|---|
| 745 | procedure TSVGText.SetFontFamily(AValue: string);
|
|---|
| 746 | begin
|
|---|
| 747 | Attribute['font-family'] := AValue;
|
|---|
| 748 | RemoveStyle('font-family');
|
|---|
| 749 | end;
|
|---|
| 750 |
|
|---|
| 751 | procedure TSVGText.SetFontItalic(AValue: boolean);
|
|---|
| 752 | begin
|
|---|
| 753 | if AValue then fontStyle:= 'italic' else fontStyle:= 'normal';
|
|---|
| 754 | end;
|
|---|
| 755 |
|
|---|
| 756 | procedure TSVGText.SetFontSize(AValue: TFloatWithCSSUnit);
|
|---|
| 757 | begin
|
|---|
| 758 | VerticalAttributeWithUnit['font-size'] := AValue;
|
|---|
| 759 | end;
|
|---|
| 760 |
|
|---|
| 761 | procedure TSVGText.SetFontStyle(AValue: string);
|
|---|
| 762 | begin
|
|---|
| 763 | Attribute['font-style'] := AValue;
|
|---|
| 764 | RemoveStyle('font-style');
|
|---|
| 765 | end;
|
|---|
| 766 |
|
|---|
| 767 | procedure TSVGText.SetFontWeight(AValue: string);
|
|---|
| 768 | begin
|
|---|
| 769 | Attribute['font-weight'] := AValue;
|
|---|
| 770 | RemoveStyle('font-weight');
|
|---|
| 771 | end;
|
|---|
| 772 |
|
|---|
| 773 | procedure TSVGText.SetSimpleText(AValue: string);
|
|---|
| 774 | begin
|
|---|
| 775 | FDomElem.TextContent := AValue;
|
|---|
| 776 | end;
|
|---|
| 777 |
|
|---|
| 778 | procedure TSVGText.SetTextDecoration(AValue: string);
|
|---|
| 779 | begin
|
|---|
| 780 | Attribute['text-decoration'] := AValue;
|
|---|
| 781 | RemoveStyle('text-decoration');
|
|---|
| 782 | end;
|
|---|
| 783 |
|
|---|
| 784 | procedure TSVGText.SetX(AValue: TFloatWithCSSUnit);
|
|---|
| 785 | begin
|
|---|
| 786 | HorizAttributeWithUnit['x'] := AValue;
|
|---|
| 787 | end;
|
|---|
| 788 |
|
|---|
| 789 | procedure TSVGText.SetY(AValue: TFloatWithCSSUnit);
|
|---|
| 790 | begin
|
|---|
| 791 | VerticalAttributeWithUnit['y'] := AValue;
|
|---|
| 792 | end;
|
|---|
| 793 |
|
|---|
| 794 | procedure TSVGText.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 795 | var
|
|---|
| 796 | fs:TFontStyles;
|
|---|
| 797 | vx,vy: single;
|
|---|
| 798 | begin
|
|---|
| 799 | ACanvas2d.beginPath;
|
|---|
| 800 | ACanvas2d.fontEmHeight := Units.ConvertHeight(fontSize,AUnit).value;
|
|---|
| 801 | ACanvas2d.fontName := fontFamily;
|
|---|
| 802 | fs := [];
|
|---|
| 803 | if fontBold then fs += [fsBold];
|
|---|
| 804 | if fontItalic then fs += [fsItalic];
|
|---|
| 805 | ACanvas2d.fontStyle := fs;
|
|---|
| 806 | vx:= Units.ConvertWidth(x,AUnit).value;
|
|---|
| 807 | vy:= Units.ConvertHeight(y,AUnit).value;
|
|---|
| 808 | ACanvas2d.text(SimpleText,vx,vy);
|
|---|
| 809 |
|
|---|
| 810 | if Assigned(GradientElement) then
|
|---|
| 811 | with ACanvas2d.measureText(SimpleText) do
|
|---|
| 812 | InitializeGradient(ACanvas2d, PointF(vx,vy),width,height,AUnit);
|
|---|
| 813 |
|
|---|
| 814 | if not isFillNone then
|
|---|
| 815 | begin
|
|---|
| 816 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 817 | ACanvas2d.fill;
|
|---|
| 818 | end;
|
|---|
| 819 | if not isStrokeNone then
|
|---|
| 820 | begin
|
|---|
| 821 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 822 | ACanvas2d.stroke;
|
|---|
| 823 | end;
|
|---|
| 824 | end;
|
|---|
| 825 |
|
|---|
| 826 | constructor TSVGText.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 827 | begin
|
|---|
| 828 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 829 | Init(ADocument,'text',AUnits);
|
|---|
| 830 | end;
|
|---|
| 831 |
|
|---|
| 832 | { TSVGGroup }
|
|---|
| 833 |
|
|---|
| 834 | constructor TSVGGroup.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 835 | begin
|
|---|
| 836 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 837 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
|---|
| 838 | end;
|
|---|
| 839 |
|
|---|
| 840 | constructor TSVGGroup.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 841 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 842 | begin
|
|---|
| 843 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
|---|
| 844 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
|---|
| 845 | end;
|
|---|
| 846 |
|
|---|
| 847 | destructor TSVGGroup.Destroy;
|
|---|
| 848 | begin
|
|---|
| 849 | FreeAndNil(FContent);
|
|---|
| 850 | inherited Destroy;
|
|---|
| 851 | end;
|
|---|
| 852 |
|
|---|
| 853 | procedure TSVGGroup.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 854 | begin
|
|---|
| 855 | FContent.Draw(ACanvas2d, AUnit);
|
|---|
| 856 | end;
|
|---|
| 857 |
|
|---|
| 858 | procedure TSVGGroup.Recompute;
|
|---|
| 859 | begin
|
|---|
| 860 | inherited Recompute;
|
|---|
| 861 | FContent.Recompute;
|
|---|
| 862 | end;
|
|---|
| 863 |
|
|---|
| 864 | { TSVGStyle }
|
|---|
| 865 |
|
|---|
| 866 | constructor TSVGStyle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 867 | begin
|
|---|
| 868 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 869 | Init(ADocument,'style',AUnits);
|
|---|
| 870 | end;
|
|---|
| 871 |
|
|---|
| 872 | constructor TSVGStyle.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 873 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 874 | begin
|
|---|
| 875 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
|---|
| 876 | Parse(AElement.TextContent);
|
|---|
| 877 | end;
|
|---|
| 878 |
|
|---|
| 879 | procedure TSVGStyle.Initialize;
|
|---|
| 880 | begin
|
|---|
| 881 | inherited Initialize;
|
|---|
| 882 | Clear;
|
|---|
| 883 | end;
|
|---|
| 884 |
|
|---|
| 885 | destructor TSVGStyle.Destroy;
|
|---|
| 886 | begin
|
|---|
| 887 | Clear;
|
|---|
| 888 | inherited Destroy;
|
|---|
| 889 | end;
|
|---|
| 890 |
|
|---|
| 891 | procedure TSVGStyle.Parse(const s: String);
|
|---|
| 892 |
|
|---|
| 893 | function IsValidAttribute(const sa: string): boolean;
|
|---|
| 894 | var
|
|---|
| 895 | i: integer;
|
|---|
| 896 | begin
|
|---|
| 897 | //(for case example "{ ; ;}")
|
|---|
| 898 | for i:= 1 to Length(sa) do
|
|---|
| 899 | if not (sa[i] in [' ',';']) then
|
|---|
| 900 | exit(true);
|
|---|
| 901 | result:= false;
|
|---|
| 902 | end;
|
|---|
| 903 |
|
|---|
| 904 | const
|
|---|
| 905 | EmptyRec: TSVGStyleItem = (name: ''; attribute: '');
|
|---|
| 906 | var
|
|---|
| 907 | i,l,pg: integer;
|
|---|
| 908 | st: String;
|
|---|
| 909 | rec: TSVGStyleItem;
|
|---|
| 910 | begin
|
|---|
| 911 | (*
|
|---|
| 912 | Example of internal style block
|
|---|
| 913 | circle {..}
|
|---|
| 914 | circle.type1 {..}
|
|---|
| 915 | .pic1 {..}
|
|---|
| 916 | *)
|
|---|
| 917 | Clear;
|
|---|
| 918 | l:= 0;
|
|---|
| 919 | pg:= 0;
|
|---|
| 920 | st:= '';
|
|---|
| 921 | rec:= EmptyRec;
|
|---|
| 922 | for i:= 1 to Length(s) do
|
|---|
| 923 | begin
|
|---|
| 924 | if s[i] = '{' then
|
|---|
| 925 | begin
|
|---|
| 926 | Inc(pg);
|
|---|
| 927 | if (pg = 1) and (Length(st) <> 0) then
|
|---|
| 928 | begin
|
|---|
| 929 | rec.name:= Trim(st);
|
|---|
| 930 | st:= '';
|
|---|
| 931 | end;
|
|---|
| 932 | end
|
|---|
| 933 | else if s[i] = '}' then
|
|---|
| 934 | begin
|
|---|
| 935 | Dec(pg);
|
|---|
| 936 | if (pg = 0) and (Length(st) <> 0) then
|
|---|
| 937 | begin
|
|---|
| 938 | if IsValidAttribute(st) then
|
|---|
| 939 | begin
|
|---|
| 940 | rec.attribute:= Trim(st);
|
|---|
| 941 | Inc(l);
|
|---|
| 942 | SetLength(FStyles,l);
|
|---|
| 943 | FStyles[l-1]:= rec;
|
|---|
| 944 | rec:= EmptyRec;
|
|---|
| 945 | end;
|
|---|
| 946 | st:= '';
|
|---|
| 947 | end;
|
|---|
| 948 | end
|
|---|
| 949 | else
|
|---|
| 950 | st:= st + s[i];
|
|---|
| 951 | end;
|
|---|
| 952 | end;
|
|---|
| 953 |
|
|---|
| 954 | function TSVGStyle.IsValidID(const sid: integer): boolean;
|
|---|
| 955 | begin
|
|---|
| 956 | result:= (sid >= 0) and (sid < Length(FStyles));
|
|---|
| 957 | end;
|
|---|
| 958 |
|
|---|
| 959 | function TSVGStyle.GetStyle(const sid: integer): TSVGStyleItem;
|
|---|
| 960 | begin
|
|---|
| 961 | if IsValidID(sid) then
|
|---|
| 962 | result:= FStyles[sid]
|
|---|
| 963 | else
|
|---|
| 964 | raise exception.Create(rsInvalidId);
|
|---|
| 965 | end;
|
|---|
| 966 |
|
|---|
| 967 | procedure TSVGStyle.SetStyle(const sid: integer; sr: TSVGStyleItem);
|
|---|
| 968 | begin
|
|---|
| 969 | if IsValidID(sid) then
|
|---|
| 970 | FStyles[sid]:= sr
|
|---|
| 971 | else
|
|---|
| 972 | raise exception.Create(rsInvalidId);
|
|---|
| 973 | end;
|
|---|
| 974 |
|
|---|
| 975 | function TSVGStyle.Count: Integer;
|
|---|
| 976 | begin
|
|---|
| 977 | result:= Length(FStyles);
|
|---|
| 978 | end;
|
|---|
| 979 |
|
|---|
| 980 | function TSVGStyle.Find(sr: TSVGStyleItem): integer;
|
|---|
| 981 | var
|
|---|
| 982 | i: integer;
|
|---|
| 983 | begin
|
|---|
| 984 | for i:= 0 to Length(FStyles)-1 do
|
|---|
| 985 | with FStyles[i] do
|
|---|
| 986 | if (name = sr.name) and
|
|---|
| 987 | (attribute = sr.attribute) then
|
|---|
| 988 | begin
|
|---|
| 989 | result:= i;
|
|---|
| 990 | Exit;
|
|---|
| 991 | end;
|
|---|
| 992 | result:= -1;
|
|---|
| 993 | end;
|
|---|
| 994 |
|
|---|
| 995 | function TSVGStyle.Find(const AName: string): integer;
|
|---|
| 996 | var
|
|---|
| 997 | i: integer;
|
|---|
| 998 | begin
|
|---|
| 999 | for i:= 0 to Length(FStyles)-1 do
|
|---|
| 1000 | with FStyles[i] do
|
|---|
| 1001 | if name = AName then
|
|---|
| 1002 | begin
|
|---|
| 1003 | result:= i;
|
|---|
| 1004 | Exit;
|
|---|
| 1005 | end;
|
|---|
| 1006 | result:= -1;
|
|---|
| 1007 | end;
|
|---|
| 1008 |
|
|---|
| 1009 | function TSVGStyle.Add(sr: TSVGStyleItem): integer;
|
|---|
| 1010 | var
|
|---|
| 1011 | l: integer;
|
|---|
| 1012 | begin
|
|---|
| 1013 | l:= Length(FStyles);
|
|---|
| 1014 | SetLength(FStyles,l+1);
|
|---|
| 1015 | FStyles[l]:= sr;
|
|---|
| 1016 | result:= l;
|
|---|
| 1017 | end;
|
|---|
| 1018 |
|
|---|
| 1019 | procedure TSVGStyle.Remove(sr: TSVGStyleItem);
|
|---|
| 1020 | var
|
|---|
| 1021 | l,p: integer;
|
|---|
| 1022 | begin
|
|---|
| 1023 | p:= Find(sr);
|
|---|
| 1024 | l:= Length(FStyles);
|
|---|
| 1025 | if p <> -1 then
|
|---|
| 1026 | begin
|
|---|
| 1027 | Finalize(FStyles[p]);
|
|---|
| 1028 | System.Move(FStyles[p+1], FStyles[p], (l-p)*SizeOf(TSVGStyleItem));
|
|---|
| 1029 | SetLength(FStyles,l-1);
|
|---|
| 1030 | end;
|
|---|
| 1031 | end;
|
|---|
| 1032 |
|
|---|
| 1033 | procedure TSVGStyle.Clear;
|
|---|
| 1034 | begin
|
|---|
| 1035 | SetLength(FStyles,0);
|
|---|
| 1036 | end;
|
|---|
| 1037 |
|
|---|
| 1038 | procedure TSVGStyle.ReParse;
|
|---|
| 1039 | begin
|
|---|
| 1040 | Parse(FDomElem.TextContent);
|
|---|
| 1041 | end;
|
|---|
| 1042 |
|
|---|
| 1043 | { TSVGRectangle }
|
|---|
| 1044 |
|
|---|
| 1045 | function TSVGRectangle.GetX: TFloatWithCSSUnit;
|
|---|
| 1046 | begin
|
|---|
| 1047 | result := HorizAttributeWithUnit['x'];
|
|---|
| 1048 | end;
|
|---|
| 1049 |
|
|---|
| 1050 | function TSVGRectangle.GetY: TFloatWithCSSUnit;
|
|---|
| 1051 | begin
|
|---|
| 1052 | result := VerticalAttributeWithUnit['y'];
|
|---|
| 1053 | end;
|
|---|
| 1054 |
|
|---|
| 1055 | function TSVGRectangle.GetWidth: TFloatWithCSSUnit;
|
|---|
| 1056 | begin
|
|---|
| 1057 | result := HorizAttributeWithUnit['width'];
|
|---|
| 1058 | end;
|
|---|
| 1059 |
|
|---|
| 1060 | function TSVGRectangle.GetHeight: TFloatWithCSSUnit;
|
|---|
| 1061 | begin
|
|---|
| 1062 | result := VerticalAttributeWithUnit['height'];
|
|---|
| 1063 | end;
|
|---|
| 1064 |
|
|---|
| 1065 | function TSVGRectangle.GetRX: TFloatWithCSSUnit;
|
|---|
| 1066 | begin
|
|---|
| 1067 | result := HorizAttributeWithUnit['rx'];
|
|---|
| 1068 | end;
|
|---|
| 1069 |
|
|---|
| 1070 | function TSVGRectangle.GetRY: TFloatWithCSSUnit;
|
|---|
| 1071 | begin
|
|---|
| 1072 | result := VerticalAttributeWithUnit['ry'];
|
|---|
| 1073 | end;
|
|---|
| 1074 |
|
|---|
| 1075 | procedure TSVGRectangle.SetX(AValue: TFloatWithCSSUnit);
|
|---|
| 1076 | begin
|
|---|
| 1077 | HorizAttributeWithUnit['x'] := AValue;
|
|---|
| 1078 | end;
|
|---|
| 1079 |
|
|---|
| 1080 | procedure TSVGRectangle.SetY(AValue: TFloatWithCSSUnit);
|
|---|
| 1081 | begin
|
|---|
| 1082 | VerticalAttributeWithUnit['y'] := AValue;
|
|---|
| 1083 | end;
|
|---|
| 1084 |
|
|---|
| 1085 | procedure TSVGRectangle.SetWidth(AValue: TFloatWithCSSUnit);
|
|---|
| 1086 | begin
|
|---|
| 1087 | HorizAttributeWithUnit['width'] := AValue;
|
|---|
| 1088 | end;
|
|---|
| 1089 |
|
|---|
| 1090 | procedure TSVGRectangle.SetHeight(AValue: TFloatWithCSSUnit);
|
|---|
| 1091 | begin
|
|---|
| 1092 | VerticalAttributeWithUnit['height'] := AValue;
|
|---|
| 1093 | end;
|
|---|
| 1094 |
|
|---|
| 1095 | procedure TSVGRectangle.SetRX(AValue: TFloatWithCSSUnit);
|
|---|
| 1096 | begin
|
|---|
| 1097 | HorizAttributeWithUnit['rx'] := AValue;
|
|---|
| 1098 | end;
|
|---|
| 1099 |
|
|---|
| 1100 | procedure TSVGRectangle.SetRY(AValue: TFloatWithCSSUnit);
|
|---|
| 1101 | begin
|
|---|
| 1102 | VerticalAttributeWithUnit['ry'] := AValue;
|
|---|
| 1103 | end;
|
|---|
| 1104 |
|
|---|
| 1105 | constructor TSVGRectangle.Create(ADocument: TXMLDocument;
|
|---|
| 1106 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1107 | begin
|
|---|
| 1108 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1109 | Init(ADocument,'rect',AUnits);
|
|---|
| 1110 | end;
|
|---|
| 1111 |
|
|---|
| 1112 | procedure TSVGRectangle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1113 | var
|
|---|
| 1114 | vx,vy,vw,vh: Single;
|
|---|
| 1115 | begin
|
|---|
| 1116 | if not isStrokeNone or not isFillNone then
|
|---|
| 1117 | begin
|
|---|
| 1118 | vx:= Units.ConvertWidth(x,AUnit).value;
|
|---|
| 1119 | vy:= Units.ConvertHeight(y,AUnit).value;
|
|---|
| 1120 | vw:= Units.ConvertWidth(width,AUnit).value;
|
|---|
| 1121 | vh:= Units.ConvertHeight(height,AUnit).value;
|
|---|
| 1122 | ACanvas2d.beginPath;
|
|---|
| 1123 | ACanvas2d.roundRect(vx,vy, vw,vh,
|
|---|
| 1124 | Units.ConvertWidth(rx,AUnit).value,Units.ConvertHeight(ry,AUnit).value);
|
|---|
| 1125 | if Assigned(GradientElement) then
|
|---|
| 1126 | InitializeGradient(ACanvas2d, PointF(vx,vy),vw,vh,AUnit);
|
|---|
| 1127 | if not isFillNone then
|
|---|
| 1128 | begin
|
|---|
| 1129 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 1130 | ACanvas2d.fill;
|
|---|
| 1131 | end;
|
|---|
| 1132 | if not isStrokeNone then
|
|---|
| 1133 | begin
|
|---|
| 1134 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1135 | ACanvas2d.stroke;
|
|---|
| 1136 | end;
|
|---|
| 1137 | end;
|
|---|
| 1138 | end;
|
|---|
| 1139 |
|
|---|
| 1140 | { TSVGPolypoints }
|
|---|
| 1141 |
|
|---|
| 1142 | function TSVGPolypoints.GetClosed: boolean;
|
|---|
| 1143 | begin
|
|---|
| 1144 | result := FDomElem.TagName = 'polygon';
|
|---|
| 1145 | end;
|
|---|
| 1146 |
|
|---|
| 1147 | function TSVGPolypoints.GetBoundingBoxF: TRectF;
|
|---|
| 1148 | begin
|
|---|
| 1149 | if not FBoundingBoxComputed then
|
|---|
| 1150 | ComputeBoundingBox(pointsF);
|
|---|
| 1151 | result := FBoundingBox;
|
|---|
| 1152 | end;
|
|---|
| 1153 |
|
|---|
| 1154 | function TSVGPolypoints.GetPoints: string;
|
|---|
| 1155 | begin
|
|---|
| 1156 | result := Attribute['points'];
|
|---|
| 1157 | end;
|
|---|
| 1158 |
|
|---|
| 1159 | function TSVGPolypoints.GetPointsF: ArrayOfTPointF;
|
|---|
| 1160 | var parser: TSVGParser;
|
|---|
| 1161 | nbcoord,i: integer;
|
|---|
| 1162 | begin
|
|---|
| 1163 | parser:=TSVGParser.Create(points);
|
|---|
| 1164 | nbcoord := 0;
|
|---|
| 1165 | repeat
|
|---|
| 1166 | parser.ParseFloat;
|
|---|
| 1167 | if not parser.NumberError then
|
|---|
| 1168 | inc(nbcoord);
|
|---|
| 1169 | until parser.NumberError or parser.Done;
|
|---|
| 1170 | parser.ClearError;
|
|---|
| 1171 | setlength(Result,nbcoord div 2);
|
|---|
| 1172 | parser.Position := 1;
|
|---|
| 1173 | for i := 0 to high(result) do
|
|---|
| 1174 | begin
|
|---|
| 1175 | result[i].x := parser.ParseFloat;
|
|---|
| 1176 | result[i].y := parser.ParseFloat;
|
|---|
| 1177 | end;
|
|---|
| 1178 | parser.Free;
|
|---|
| 1179 | end;
|
|---|
| 1180 |
|
|---|
| 1181 | procedure TSVGPolypoints.SetPoints(AValue: string);
|
|---|
| 1182 | begin
|
|---|
| 1183 | Attribute['points'] := AValue;
|
|---|
| 1184 | end;
|
|---|
| 1185 |
|
|---|
| 1186 | procedure TSVGPolypoints.SetPointsF(AValue: ArrayOfTPointF);
|
|---|
| 1187 | var s: string;
|
|---|
| 1188 | i: integer;
|
|---|
| 1189 | begin
|
|---|
| 1190 | s:= '';
|
|---|
| 1191 | for i := 0 to high(AValue) do
|
|---|
| 1192 | begin
|
|---|
| 1193 | if s <> '' then s += ' ';
|
|---|
| 1194 | with AValue[i] do
|
|---|
| 1195 | s += TCSSUnitConverter.formatValue(x)+' '+TCSSUnitConverter.formatValue(y);
|
|---|
| 1196 | end;
|
|---|
| 1197 | points := s;
|
|---|
| 1198 | ComputeBoundingBox(AValue);
|
|---|
| 1199 | end;
|
|---|
| 1200 |
|
|---|
| 1201 | procedure TSVGPolypoints.ComputeBoundingBox(APoints: ArrayOfTPointF);
|
|---|
| 1202 | var
|
|---|
| 1203 | i: Integer;
|
|---|
| 1204 | begin
|
|---|
| 1205 | if length(APoints) > 1 then
|
|---|
| 1206 | begin
|
|---|
| 1207 | with APoints[0] do
|
|---|
| 1208 | FBoundingBox:= RectF(x,y,x,y);
|
|---|
| 1209 | for i:= 1 to high(APoints) do
|
|---|
| 1210 | with APoints[i] do
|
|---|
| 1211 | begin
|
|---|
| 1212 | if x < FBoundingBox.Left then
|
|---|
| 1213 | FBoundingBox.Left:= x
|
|---|
| 1214 | else if x > FBoundingBox.Right then
|
|---|
| 1215 | FBoundingBox.Right:= x;
|
|---|
| 1216 | if y < FBoundingBox.Top then
|
|---|
| 1217 | FBoundingBox.Top:= y
|
|---|
| 1218 | else if y > FBoundingBox.Bottom then
|
|---|
| 1219 | FBoundingBox.Bottom:= y;
|
|---|
| 1220 | end;
|
|---|
| 1221 | FBoundingBoxComputed := true;
|
|---|
| 1222 | end else
|
|---|
| 1223 | begin
|
|---|
| 1224 | FBoundingBox := RectF(0,0,0,0);
|
|---|
| 1225 | FBoundingBoxComputed := true;
|
|---|
| 1226 | end;
|
|---|
| 1227 | end;
|
|---|
| 1228 |
|
|---|
| 1229 | constructor TSVGPolypoints.Create(ADocument: TXMLDocument;
|
|---|
| 1230 | AUnits: TCSSUnitConverter; AClosed: boolean; ADataLink: TSVGDataLink);
|
|---|
| 1231 | begin
|
|---|
| 1232 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1233 | if AClosed then
|
|---|
| 1234 | Init(ADocument, 'polygon', AUnits)
|
|---|
| 1235 | else
|
|---|
| 1236 | Init(ADocument, 'polyline', AUnits);
|
|---|
| 1237 | end;
|
|---|
| 1238 |
|
|---|
| 1239 | destructor TSVGPolypoints.Destroy;
|
|---|
| 1240 | begin
|
|---|
| 1241 | inherited Destroy;
|
|---|
| 1242 | end;
|
|---|
| 1243 |
|
|---|
| 1244 | procedure TSVGPolypoints.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1245 | var
|
|---|
| 1246 | prevMatrix: TAffineMatrix;
|
|---|
| 1247 | pts: ArrayOfTPointF;
|
|---|
| 1248 | begin
|
|---|
| 1249 | if isFillNone and isStrokeNone then exit;
|
|---|
| 1250 | if AUnit <> cuCustom then
|
|---|
| 1251 | begin
|
|---|
| 1252 | prevMatrix := ACanvas2d.matrix;
|
|---|
| 1253 | ACanvas2d.scale(Units.ConvertWidth(1,cuCustom,AUnit),
|
|---|
| 1254 | Units.ConvertHeight(1,cuCustom,AUnit));
|
|---|
| 1255 | InternalDraw(ACanvas2d, cuCustom);
|
|---|
| 1256 | ACanvas2d.matrix:= prevMatrix;
|
|---|
| 1257 | end else
|
|---|
| 1258 | begin
|
|---|
| 1259 | ACanvas2d.beginPath;
|
|---|
| 1260 | pts := pointsF;
|
|---|
| 1261 | ACanvas2d.polylineTo(pts);
|
|---|
| 1262 | if closed then ACanvas2d.closePath;
|
|---|
| 1263 |
|
|---|
| 1264 | with boundingBoxF do
|
|---|
| 1265 | InitializeGradient(ACanvas2d,
|
|---|
| 1266 | PointF(Left,Top),abs(Right-Left),abs(Bottom-Top),AUnit);
|
|---|
| 1267 |
|
|---|
| 1268 | if not isFillNone then
|
|---|
| 1269 | begin
|
|---|
| 1270 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 1271 | ACanvas2d.fill;
|
|---|
| 1272 | end;
|
|---|
| 1273 | if not isStrokeNone then
|
|---|
| 1274 | begin
|
|---|
| 1275 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1276 | ACanvas2d.stroke;
|
|---|
| 1277 | end;
|
|---|
| 1278 | end;
|
|---|
| 1279 | end;
|
|---|
| 1280 |
|
|---|
| 1281 | { TSVGPath }
|
|---|
| 1282 |
|
|---|
| 1283 | function TSVGPath.GetPathLength: TFloatWithCSSUnit;
|
|---|
| 1284 | begin
|
|---|
| 1285 | result := OrthoAttributeWithUnit['pathLength'];
|
|---|
| 1286 | end;
|
|---|
| 1287 |
|
|---|
| 1288 | function TSVGPath.GetPath: TBGRAPath;
|
|---|
| 1289 | begin
|
|---|
| 1290 | if FPath = nil then
|
|---|
| 1291 | FPath := TBGRAPath.Create(Attribute['d']);
|
|---|
| 1292 | result := FPath;
|
|---|
| 1293 | end;
|
|---|
| 1294 |
|
|---|
| 1295 | function TSVGPath.GetBoundingBoxF: TRectF;
|
|---|
| 1296 | begin
|
|---|
| 1297 | if not FBoundingBoxComputed then
|
|---|
| 1298 | begin
|
|---|
| 1299 | FBoundingBox := path.GetBounds;
|
|---|
| 1300 | FBoundingBoxComputed := true;
|
|---|
| 1301 | end;
|
|---|
| 1302 | result := FBoundingBox;
|
|---|
| 1303 | end;
|
|---|
| 1304 |
|
|---|
| 1305 | function TSVGPath.GetData: string;
|
|---|
| 1306 | begin
|
|---|
| 1307 | if FPath = nil then
|
|---|
| 1308 | result := Attribute['d']
|
|---|
| 1309 | else
|
|---|
| 1310 | result := FPath.SvgString;
|
|---|
| 1311 | end;
|
|---|
| 1312 |
|
|---|
| 1313 | procedure TSVGPath.SetPathLength(AValue: TFloatWithCSSUnit);
|
|---|
| 1314 | begin
|
|---|
| 1315 | OrthoAttributeWithUnit['pathLength'] := AValue;
|
|---|
| 1316 | end;
|
|---|
| 1317 |
|
|---|
| 1318 | procedure TSVGPath.SetData(AValue: string);
|
|---|
| 1319 | begin
|
|---|
| 1320 | if FPath = nil then
|
|---|
| 1321 | Attribute['d'] := AValue
|
|---|
| 1322 | else
|
|---|
| 1323 | FPath.SvgString := AValue;
|
|---|
| 1324 | FBoundingBoxComputed := false;
|
|---|
| 1325 | end;
|
|---|
| 1326 |
|
|---|
| 1327 | function TSVGPath.GetDOMElement: TDOMElement;
|
|---|
| 1328 | begin
|
|---|
| 1329 | if FPath <> nil then Attribute['d'] := FPath.SvgString;
|
|---|
| 1330 | Result:=inherited GetDOMElement;
|
|---|
| 1331 | end;
|
|---|
| 1332 |
|
|---|
| 1333 | constructor TSVGPath.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1334 | begin
|
|---|
| 1335 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1336 | Init(ADocument,'path',AUnits);
|
|---|
| 1337 | FPath := nil;
|
|---|
| 1338 | FBoundingBoxComputed := false;
|
|---|
| 1339 | FBoundingBox := rectF(0,0,0,0);
|
|---|
| 1340 | end;
|
|---|
| 1341 |
|
|---|
| 1342 | constructor TSVGPath.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 1343 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1344 | begin
|
|---|
| 1345 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
|---|
| 1346 | Init(ADocument, AElement, AUnits);
|
|---|
| 1347 | FPath := nil;
|
|---|
| 1348 | FBoundingBoxComputed := false;
|
|---|
| 1349 | FBoundingBox := rectF(0,0,0,0);
|
|---|
| 1350 | end;
|
|---|
| 1351 |
|
|---|
| 1352 | destructor TSVGPath.Destroy;
|
|---|
| 1353 | begin
|
|---|
| 1354 | FreeAndNil(FPath);
|
|---|
| 1355 | inherited Destroy;
|
|---|
| 1356 | end;
|
|---|
| 1357 |
|
|---|
| 1358 | procedure TSVGPath.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1359 | var
|
|---|
| 1360 | prevMatrix: TAffineMatrix;
|
|---|
| 1361 | begin
|
|---|
| 1362 | if isFillNone and isStrokeNone then exit;
|
|---|
| 1363 | if AUnit <> cuCustom then
|
|---|
| 1364 | begin
|
|---|
| 1365 | prevMatrix := ACanvas2d.matrix;
|
|---|
| 1366 | ACanvas2d.scale(Units.ConvertWidth(1,cuCustom,AUnit),
|
|---|
| 1367 | Units.ConvertHeight(1,cuCustom,AUnit));
|
|---|
| 1368 | InternalDraw(ACanvas2d, cuCustom);
|
|---|
| 1369 | ACanvas2d.matrix:= prevMatrix;
|
|---|
| 1370 | end else
|
|---|
| 1371 | begin
|
|---|
| 1372 | ACanvas2d.path(path);
|
|---|
| 1373 | if Assigned(GradientElement) then
|
|---|
| 1374 | with boundingBoxF do
|
|---|
| 1375 | InitializeGradient(ACanvas2d,
|
|---|
| 1376 | PointF(Left,Top),abs(Right-Left),abs(Bottom-Top),AUnit);
|
|---|
| 1377 | if not isFillNone then
|
|---|
| 1378 | begin
|
|---|
| 1379 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 1380 | ACanvas2d.fill;
|
|---|
| 1381 | end;
|
|---|
| 1382 | if not isStrokeNone then
|
|---|
| 1383 | begin
|
|---|
| 1384 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1385 | ACanvas2d.stroke;
|
|---|
| 1386 | end;
|
|---|
| 1387 | end;
|
|---|
| 1388 | end;
|
|---|
| 1389 |
|
|---|
| 1390 | { TSVGEllipse }
|
|---|
| 1391 |
|
|---|
| 1392 | function TSVGEllipse.GetCX: TFloatWithCSSUnit;
|
|---|
| 1393 | begin
|
|---|
| 1394 | result := HorizAttributeWithUnit['cx'];
|
|---|
| 1395 | end;
|
|---|
| 1396 |
|
|---|
| 1397 | function TSVGEllipse.GetCY: TFloatWithCSSUnit;
|
|---|
| 1398 | begin
|
|---|
| 1399 | result := VerticalAttributeWithUnit['cy'];
|
|---|
| 1400 | end;
|
|---|
| 1401 |
|
|---|
| 1402 | function TSVGEllipse.GetRX: TFloatWithCSSUnit;
|
|---|
| 1403 | begin
|
|---|
| 1404 | result := HorizAttributeWithUnit['rx'];
|
|---|
| 1405 | end;
|
|---|
| 1406 |
|
|---|
| 1407 | function TSVGEllipse.GetRY: TFloatWithCSSUnit;
|
|---|
| 1408 | begin
|
|---|
| 1409 | result := VerticalAttributeWithUnit['ry'];
|
|---|
| 1410 | end;
|
|---|
| 1411 |
|
|---|
| 1412 | procedure TSVGEllipse.SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 1413 | begin
|
|---|
| 1414 | HorizAttributeWithUnit['cx'] := AValue;
|
|---|
| 1415 | end;
|
|---|
| 1416 |
|
|---|
| 1417 | procedure TSVGEllipse.SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 1418 | begin
|
|---|
| 1419 | VerticalAttributeWithUnit['cy'] := AValue;
|
|---|
| 1420 | end;
|
|---|
| 1421 |
|
|---|
| 1422 | procedure TSVGEllipse.SetRX(AValue: TFloatWithCSSUnit);
|
|---|
| 1423 | begin
|
|---|
| 1424 | HorizAttributeWithUnit['rx'] := AValue;
|
|---|
| 1425 | end;
|
|---|
| 1426 |
|
|---|
| 1427 | procedure TSVGEllipse.SetRY(AValue: TFloatWithCSSUnit);
|
|---|
| 1428 | begin
|
|---|
| 1429 | VerticalAttributeWithUnit['ry'] := AValue;
|
|---|
| 1430 | end;
|
|---|
| 1431 |
|
|---|
| 1432 | constructor TSVGEllipse.Create(ADocument: TXMLDocument;
|
|---|
| 1433 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1434 | begin
|
|---|
| 1435 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1436 | Init(ADocument,'ellipse',AUnits);
|
|---|
| 1437 | end;
|
|---|
| 1438 |
|
|---|
| 1439 | procedure TSVGEllipse.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1440 | var
|
|---|
| 1441 | vcx,vcy,vrx,vry: Single;
|
|---|
| 1442 | begin
|
|---|
| 1443 | if not isFillNone or not isStrokeNone then
|
|---|
| 1444 | begin
|
|---|
| 1445 | vcx:= Units.ConvertWidth(cx,AUnit).value;
|
|---|
| 1446 | vcy:= Units.ConvertHeight(cy,AUnit).value;
|
|---|
| 1447 | vrx:= Units.ConvertWidth(rx,AUnit).value;
|
|---|
| 1448 | vry:= Units.ConvertHeight(ry,AUnit).value;
|
|---|
| 1449 | ACanvas2d.beginPath;
|
|---|
| 1450 | ACanvas2d.ellipse(vcx,vcy,vrx,vry);
|
|---|
| 1451 | if Assigned(GradientElement) then
|
|---|
| 1452 | InitializeGradient(ACanvas2d, PointF(vcx-vrx,vcy-vry),vrx*2,vry*2,AUnit);
|
|---|
| 1453 | if not isFillNone then
|
|---|
| 1454 | begin
|
|---|
| 1455 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 1456 | ACanvas2d.fill;
|
|---|
| 1457 | end;
|
|---|
| 1458 | if not isStrokeNone then
|
|---|
| 1459 | begin
|
|---|
| 1460 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1461 | ACanvas2d.stroke;
|
|---|
| 1462 | end;
|
|---|
| 1463 | end;
|
|---|
| 1464 | end;
|
|---|
| 1465 |
|
|---|
| 1466 | { TSVGCircle }
|
|---|
| 1467 |
|
|---|
| 1468 | function TSVGCircle.GetCX: TFloatWithCSSUnit;
|
|---|
| 1469 | begin
|
|---|
| 1470 | result := HorizAttributeWithUnit['cx'];
|
|---|
| 1471 | end;
|
|---|
| 1472 |
|
|---|
| 1473 | function TSVGCircle.GetCY: TFloatWithCSSUnit;
|
|---|
| 1474 | begin
|
|---|
| 1475 | result := VerticalAttributeWithUnit['cy'];
|
|---|
| 1476 | end;
|
|---|
| 1477 |
|
|---|
| 1478 | function TSVGCircle.GetR: TFloatWithCSSUnit;
|
|---|
| 1479 | begin
|
|---|
| 1480 | result := OrthoAttributeWithUnit['r'];
|
|---|
| 1481 | end;
|
|---|
| 1482 |
|
|---|
| 1483 | procedure TSVGCircle.SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 1484 | begin
|
|---|
| 1485 | HorizAttributeWithUnit['cx'] := AValue;
|
|---|
| 1486 | end;
|
|---|
| 1487 |
|
|---|
| 1488 | procedure TSVGCircle.SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 1489 | begin
|
|---|
| 1490 | VerticalAttributeWithUnit['cy'] := AValue;
|
|---|
| 1491 | end;
|
|---|
| 1492 |
|
|---|
| 1493 | procedure TSVGCircle.SetR(AValue: TFloatWithCSSUnit);
|
|---|
| 1494 | begin
|
|---|
| 1495 | OrthoAttributeWithUnit['r'] := AValue;
|
|---|
| 1496 | end;
|
|---|
| 1497 |
|
|---|
| 1498 | constructor TSVGCircle.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1499 | begin
|
|---|
| 1500 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1501 | Init(ADocument,'circle',AUnits);
|
|---|
| 1502 | end;
|
|---|
| 1503 |
|
|---|
| 1504 | procedure TSVGCircle.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1505 | var
|
|---|
| 1506 | vcx,vcy,vr: Single;
|
|---|
| 1507 | begin
|
|---|
| 1508 | if not isFillNone or not isStrokeNone then
|
|---|
| 1509 | begin
|
|---|
| 1510 | vcx:= Units.ConvertWidth(cx,AUnit).value;
|
|---|
| 1511 | vcy:= Units.ConvertHeight(cy,AUnit).value;
|
|---|
| 1512 | vr:= Units.ConvertWidth(r,AUnit).value;
|
|---|
| 1513 | ACanvas2d.beginPath;
|
|---|
| 1514 | ACanvas2d.circle(vcx,vcy,vr);
|
|---|
| 1515 | if Assigned(GradientElement) then
|
|---|
| 1516 | InitializeGradient(ACanvas2d, PointF(vcx-vr,vcy-vr),vr*2,vr*2,AUnit);
|
|---|
| 1517 | if not isFillNone then
|
|---|
| 1518 | begin
|
|---|
| 1519 | ApplyFillStyle(ACanvas2D,AUnit);
|
|---|
| 1520 | ACanvas2d.fill;
|
|---|
| 1521 | end;
|
|---|
| 1522 | if not isStrokeNone then
|
|---|
| 1523 | begin
|
|---|
| 1524 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1525 | ACanvas2d.stroke;
|
|---|
| 1526 | end;
|
|---|
| 1527 | end;
|
|---|
| 1528 | end;
|
|---|
| 1529 |
|
|---|
| 1530 | { TSVGLine }
|
|---|
| 1531 |
|
|---|
| 1532 | function TSVGLine.GetX1: TFloatWithCSSUnit;
|
|---|
| 1533 | begin
|
|---|
| 1534 | result := HorizAttributeWithUnit['x1'];
|
|---|
| 1535 | end;
|
|---|
| 1536 |
|
|---|
| 1537 | function TSVGLine.GetX2: TFloatWithCSSUnit;
|
|---|
| 1538 | begin
|
|---|
| 1539 | result := HorizAttributeWithUnit['x2'];
|
|---|
| 1540 | end;
|
|---|
| 1541 |
|
|---|
| 1542 | function TSVGLine.GetY1: TFloatWithCSSUnit;
|
|---|
| 1543 | begin
|
|---|
| 1544 | result := VerticalAttributeWithUnit['y1'];
|
|---|
| 1545 | end;
|
|---|
| 1546 |
|
|---|
| 1547 | function TSVGLine.GetY2: TFloatWithCSSUnit;
|
|---|
| 1548 | begin
|
|---|
| 1549 | result := VerticalAttributeWithUnit['y2'];
|
|---|
| 1550 | end;
|
|---|
| 1551 |
|
|---|
| 1552 | procedure TSVGLine.SetX1(AValue: TFloatWithCSSUnit);
|
|---|
| 1553 | begin
|
|---|
| 1554 | HorizAttributeWithUnit['x1'] := AValue;
|
|---|
| 1555 | end;
|
|---|
| 1556 |
|
|---|
| 1557 | procedure TSVGLine.SetX2(AValue: TFloatWithCSSUnit);
|
|---|
| 1558 | begin
|
|---|
| 1559 | HorizAttributeWithUnit['x2'] := AValue;
|
|---|
| 1560 | end;
|
|---|
| 1561 |
|
|---|
| 1562 | procedure TSVGLine.SetY1(AValue: TFloatWithCSSUnit);
|
|---|
| 1563 | begin
|
|---|
| 1564 | VerticalAttributeWithUnit['y1'] := AValue;
|
|---|
| 1565 | end;
|
|---|
| 1566 |
|
|---|
| 1567 | procedure TSVGLine.SetY2(AValue: TFloatWithCSSUnit);
|
|---|
| 1568 | begin
|
|---|
| 1569 | VerticalAttributeWithUnit['y2'] := AValue;
|
|---|
| 1570 | end;
|
|---|
| 1571 |
|
|---|
| 1572 | constructor TSVGLine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1573 | begin
|
|---|
| 1574 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1575 | Init(ADocument,'line',AUnits);
|
|---|
| 1576 | end;
|
|---|
| 1577 |
|
|---|
| 1578 | procedure TSVGLine.InternalDraw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 1579 | begin
|
|---|
| 1580 | if not isStrokeNone then
|
|---|
| 1581 | begin
|
|---|
| 1582 | ApplyStrokeStyle(ACanvas2D,AUnit);
|
|---|
| 1583 | ACanvas2d.beginPath;
|
|---|
| 1584 | ACanvas2d.moveTo(Units.ConvertWidth(x1,AUnit).value,Units.ConvertHeight(y1,AUnit).value);
|
|---|
| 1585 | ACanvas2d.lineTo(Units.ConvertWidth(x2,AUnit).value,Units.ConvertHeight(y2,AUnit).value);
|
|---|
| 1586 | ACanvas2d.stroke;
|
|---|
| 1587 | end;
|
|---|
| 1588 | end;
|
|---|
| 1589 |
|
|---|
| 1590 | { TSVGGradient } //##
|
|---|
| 1591 |
|
|---|
| 1592 | function TSVGGradient.GetHRef: string;
|
|---|
| 1593 | begin
|
|---|
| 1594 | result := Attribute['xlink:href'];
|
|---|
| 1595 | if result = '' then
|
|---|
| 1596 | result := Attribute['href'];//(Note: specific for svg 2)
|
|---|
| 1597 | end;
|
|---|
| 1598 |
|
|---|
| 1599 | function TSVGGradient.GetUseObjectBoundingBox: boolean;
|
|---|
| 1600 | begin
|
|---|
| 1601 | result := (gradientUnits = 'objectBoundingBox');
|
|---|
| 1602 | end;
|
|---|
| 1603 |
|
|---|
| 1604 | procedure TSVGGradient.SetGradientTransform(AValue: string);
|
|---|
| 1605 | begin
|
|---|
| 1606 | Attribute['gradientTransform'] := AValue;
|
|---|
| 1607 | end;
|
|---|
| 1608 |
|
|---|
| 1609 | function TSVGGradient.GetGradientUnits: string;
|
|---|
| 1610 | begin
|
|---|
| 1611 | result := AttributeDef['gradientUnits','objectBoundingBox'];
|
|---|
| 1612 | end;
|
|---|
| 1613 |
|
|---|
| 1614 | function TSVGGradient.GetGradientTransform: string;
|
|---|
| 1615 | begin
|
|---|
| 1616 | result := Attribute['gradientTransform'];
|
|---|
| 1617 | end;
|
|---|
| 1618 |
|
|---|
| 1619 | function TSVGGradient.GetGradientMatrix(AUnit: TCSSUnit): TAffineMatrix;
|
|---|
| 1620 | var parser: TSVGParser;
|
|---|
| 1621 | s: string;
|
|---|
| 1622 | begin
|
|---|
| 1623 | s := gradientTransform;
|
|---|
| 1624 | if s = '' then
|
|---|
| 1625 | begin
|
|---|
| 1626 | result := AffineMatrixIdentity;
|
|---|
| 1627 | exit;
|
|---|
| 1628 | end;
|
|---|
| 1629 | parser := TSVGParser.Create(s);
|
|---|
| 1630 | result := parser.ParseTransform;
|
|---|
| 1631 | parser.Free;
|
|---|
| 1632 | result[1,3] := Units.ConvertWidth(result[1,3],cuCustom,AUnit);
|
|---|
| 1633 | result[2,3] := Units.ConvertHeight(result[2,3],cuCustom,AUnit);
|
|---|
| 1634 | end;
|
|---|
| 1635 |
|
|---|
| 1636 | procedure TSVGGradient.SetGradientUnits(AValue: string);
|
|---|
| 1637 | begin
|
|---|
| 1638 | Attribute['gradientUnits'] := AValue;
|
|---|
| 1639 | end;
|
|---|
| 1640 |
|
|---|
| 1641 | procedure TSVGGradient.SetHRef(AValue: string);
|
|---|
| 1642 | begin
|
|---|
| 1643 | Attribute['xlink:href'] := AValue;
|
|---|
| 1644 | end;
|
|---|
| 1645 |
|
|---|
| 1646 | constructor TSVGGradient.Create(ADocument: TXMLDocument;
|
|---|
| 1647 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1648 | begin
|
|---|
| 1649 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1650 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
|---|
| 1651 | end;
|
|---|
| 1652 |
|
|---|
| 1653 | function TSVGGradient.HRefToGradientID(const AValue: string): string;
|
|---|
| 1654 | var
|
|---|
| 1655 | l: integer;
|
|---|
| 1656 | begin
|
|---|
| 1657 | //(example input: "#gradient1")
|
|---|
| 1658 | l:= Length(AValue);
|
|---|
| 1659 | if l < 2 then
|
|---|
| 1660 | result:= ''
|
|---|
| 1661 | else
|
|---|
| 1662 | result:= System.Copy(AValue,2,l-1);
|
|---|
| 1663 | end;
|
|---|
| 1664 |
|
|---|
| 1665 | function TSVGGradient.FindGradientRef(const AGradientID: string): integer;
|
|---|
| 1666 | var
|
|---|
| 1667 | i: integer;
|
|---|
| 1668 | begin
|
|---|
| 1669 | with FDataLink do
|
|---|
| 1670 | for i:= 0 to GradientCount-1 do
|
|---|
| 1671 | if (Gradients[i] as TSVGGradient).ID = AGradientID then
|
|---|
| 1672 | begin
|
|---|
| 1673 | result:= i;
|
|---|
| 1674 | exit;
|
|---|
| 1675 | end;
|
|---|
| 1676 | result:= -1;
|
|---|
| 1677 | end;
|
|---|
| 1678 |
|
|---|
| 1679 | procedure TSVGGradient.Initialize;
|
|---|
| 1680 | begin
|
|---|
| 1681 | inherited;
|
|---|
| 1682 | InheritedGradients:= TSVGElementList.Create;
|
|---|
| 1683 | end;
|
|---|
| 1684 |
|
|---|
| 1685 | function TSVGGradient.GetInheritedAttribute(AValue: string;
|
|---|
| 1686 | AConvMethod: TConvMethod; ADefault: TFloatWithCSSUnit): TFloatWithCSSUnit;
|
|---|
| 1687 | var
|
|---|
| 1688 | i: integer;
|
|---|
| 1689 | el: TSVGGradient;
|
|---|
| 1690 | invalidDef: TFloatWithCSSUnit;
|
|---|
| 1691 | begin
|
|---|
| 1692 | invalidDef:= FloatWithCSSUnit(EmptySingle,cuPercent);
|
|---|
| 1693 | //find valid inherited attribute (start from "self": item[0])
|
|---|
| 1694 | for i:= 0 to InheritedGradients.Count-1 do
|
|---|
| 1695 | begin
|
|---|
| 1696 | el:= TSVGGradient( InheritedGradients[i] );
|
|---|
| 1697 | with el do
|
|---|
| 1698 | begin
|
|---|
| 1699 | if AConvMethod = cmHoriz then
|
|---|
| 1700 | result:= HorizAttributeWithUnitDef[AValue,invalidDef]
|
|---|
| 1701 | else if AConvMethod = cmVertical then
|
|---|
| 1702 | result:= VerticalAttributeWithUnitDef[AValue,invalidDef]
|
|---|
| 1703 | else if AConvMethod = cmOrtho then
|
|---|
| 1704 | result:= OrthoAttributeWithUnitDef[AValue,invalidDef]
|
|---|
| 1705 | else
|
|---|
| 1706 | result:= AttributeWithUnitDef[AValue,invalidDef];
|
|---|
| 1707 |
|
|---|
| 1708 | if (result.value <> invalidDef.value) or
|
|---|
| 1709 | (result.CSSUnit <> invalidDef.CSSUnit) then
|
|---|
| 1710 | exit;
|
|---|
| 1711 | end;
|
|---|
| 1712 | end;
|
|---|
| 1713 | result:= ADefault;
|
|---|
| 1714 | end;
|
|---|
| 1715 |
|
|---|
| 1716 | constructor TSVGGradient.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 1717 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1718 | begin
|
|---|
| 1719 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
|---|
| 1720 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
|---|
| 1721 | end;
|
|---|
| 1722 |
|
|---|
| 1723 | destructor TSVGGradient.Destroy;
|
|---|
| 1724 | begin
|
|---|
| 1725 | FreeAndNil(FContent);
|
|---|
| 1726 | FreeAndNil(InheritedGradients);
|
|---|
| 1727 | inherited Destroy;
|
|---|
| 1728 | end;
|
|---|
| 1729 |
|
|---|
| 1730 | procedure TSVGGradient.Recompute;
|
|---|
| 1731 | begin
|
|---|
| 1732 | inherited Recompute;
|
|---|
| 1733 | FContent.Recompute;
|
|---|
| 1734 | end;
|
|---|
| 1735 |
|
|---|
| 1736 | procedure TSVGGradient.ScanInheritedGradients(const forceScan: boolean = false);
|
|---|
| 1737 | var
|
|---|
| 1738 | el: TSVGGradient;
|
|---|
| 1739 | pos: integer;
|
|---|
| 1740 | gradientID: string;
|
|---|
| 1741 | begin
|
|---|
| 1742 | //(if list empty = not scan)
|
|---|
| 1743 | if (InheritedGradients.Count <> 0) and (not forceScan) then
|
|---|
| 1744 | exit;
|
|---|
| 1745 |
|
|---|
| 1746 | InheritedGradients.Clear;
|
|---|
| 1747 | InheritedGradients.Add(Self);//(important)
|
|---|
| 1748 | el:= Self;
|
|---|
| 1749 | while el.hRef <> '' do
|
|---|
| 1750 | begin
|
|---|
| 1751 | gradientID:= HRefToGradientID(el.hRef);
|
|---|
| 1752 | pos:= FindGradientRef(gradientID);
|
|---|
| 1753 | if pos = -1 then
|
|---|
| 1754 | exit
|
|---|
| 1755 | else
|
|---|
| 1756 | begin
|
|---|
| 1757 | el:= TSVGGradient(FDataLink.Gradients[pos]);
|
|---|
| 1758 | InheritedGradients.Add(el);
|
|---|
| 1759 | end;
|
|---|
| 1760 | end;
|
|---|
| 1761 | end;
|
|---|
| 1762 |
|
|---|
| 1763 | { TSVGLinearGradient }
|
|---|
| 1764 |
|
|---|
| 1765 | function TSVGLinearGradient.GetX1: TFloatWithCSSUnit;
|
|---|
| 1766 | begin
|
|---|
| 1767 | result := GetInheritedAttribute('x1',cmNone,FloatWithCSSUnit(0,cuPercent));
|
|---|
| 1768 | end;
|
|---|
| 1769 |
|
|---|
| 1770 | function TSVGLinearGradient.GetX2: TFloatWithCSSUnit;
|
|---|
| 1771 | begin
|
|---|
| 1772 | result := GetInheritedAttribute('x2',cmNone,FloatWithCSSUnit(100,cuPercent));
|
|---|
| 1773 | end;
|
|---|
| 1774 |
|
|---|
| 1775 | function TSVGLinearGradient.GetY1: TFloatWithCSSUnit;
|
|---|
| 1776 | begin
|
|---|
| 1777 | result := GetInheritedAttribute('y1',cmNone,FloatWithCSSUnit(0,cuPercent));
|
|---|
| 1778 | end;
|
|---|
| 1779 |
|
|---|
| 1780 | function TSVGLinearGradient.GetY2: TFloatWithCSSUnit;
|
|---|
| 1781 | begin
|
|---|
| 1782 | result := GetInheritedAttribute('y2',cmNone,FloatWithCSSUnit(0,cuPercent));
|
|---|
| 1783 | end;
|
|---|
| 1784 |
|
|---|
| 1785 | procedure TSVGLinearGradient.SetX1(AValue: TFloatWithCSSUnit);
|
|---|
| 1786 | begin
|
|---|
| 1787 | AttributeWithUnit['x1']:= AValue;
|
|---|
| 1788 | end;
|
|---|
| 1789 |
|
|---|
| 1790 | procedure TSVGLinearGradient.SetX2(AValue: TFloatWithCSSUnit);
|
|---|
| 1791 | begin
|
|---|
| 1792 | AttributeWithUnit['x2']:= AValue;
|
|---|
| 1793 | end;
|
|---|
| 1794 |
|
|---|
| 1795 | procedure TSVGLinearGradient.SetY1(AValue: TFloatWithCSSUnit);
|
|---|
| 1796 | begin
|
|---|
| 1797 | AttributeWithUnit['y1']:= AValue;
|
|---|
| 1798 | end;
|
|---|
| 1799 |
|
|---|
| 1800 | procedure TSVGLinearGradient.SetY2(AValue: TFloatWithCSSUnit);
|
|---|
| 1801 | begin
|
|---|
| 1802 | AttributeWithUnit['y2']:= AValue;
|
|---|
| 1803 | end;
|
|---|
| 1804 |
|
|---|
| 1805 | constructor TSVGLinearGradient.Create(ADocument: TXMLDocument;
|
|---|
| 1806 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1807 | begin
|
|---|
| 1808 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1809 | Init(ADocument,'linearGradient',AUnits);
|
|---|
| 1810 | end;
|
|---|
| 1811 |
|
|---|
| 1812 | { TSVGRadialGradient }
|
|---|
| 1813 |
|
|---|
| 1814 | function TSVGRadialGradient.GetCX: TFloatWithCSSUnit;
|
|---|
| 1815 | begin
|
|---|
| 1816 | result := GetInheritedAttribute('cx',cmHoriz,FloatWithCSSUnit(50,cuPercent));
|
|---|
| 1817 | end;
|
|---|
| 1818 |
|
|---|
| 1819 | function TSVGRadialGradient.GetCY: TFloatWithCSSUnit;
|
|---|
| 1820 | begin
|
|---|
| 1821 | result := GetInheritedAttribute('cy',cmVertical,FloatWithCSSUnit(50,cuPercent));
|
|---|
| 1822 | end;
|
|---|
| 1823 |
|
|---|
| 1824 | function TSVGRadialGradient.GetR: TFloatWithCSSUnit;
|
|---|
| 1825 | begin
|
|---|
| 1826 | result := GetInheritedAttribute('r',cmOrtho,FloatWithCSSUnit(50,cuPercent));
|
|---|
| 1827 | end;
|
|---|
| 1828 |
|
|---|
| 1829 | function TSVGRadialGradient.GetFX: TFloatWithCSSUnit;
|
|---|
| 1830 | begin
|
|---|
| 1831 | result := GetInheritedAttribute('fx',cmHoriz,cx);
|
|---|
| 1832 | end;
|
|---|
| 1833 |
|
|---|
| 1834 | function TSVGRadialGradient.GetFY: TFloatWithCSSUnit;
|
|---|
| 1835 | begin
|
|---|
| 1836 | result := GetInheritedAttribute('fy',cmVertical,cy);
|
|---|
| 1837 | end;
|
|---|
| 1838 |
|
|---|
| 1839 | function TSVGRadialGradient.GetFR: TFloatWithCSSUnit;
|
|---|
| 1840 | begin
|
|---|
| 1841 | result := GetInheritedAttribute('fr',cmHoriz,FloatWithCSSUnit(0,cuPercent));
|
|---|
| 1842 | end;
|
|---|
| 1843 |
|
|---|
| 1844 | procedure TSVGRadialGradient.SetCX(AValue: TFloatWithCSSUnit);
|
|---|
| 1845 | begin
|
|---|
| 1846 | HorizAttributeWithUnit['cx'] := AValue;
|
|---|
| 1847 | end;
|
|---|
| 1848 |
|
|---|
| 1849 | procedure TSVGRadialGradient.SetCY(AValue: TFloatWithCSSUnit);
|
|---|
| 1850 | begin
|
|---|
| 1851 | VerticalAttributeWithUnit['cy'] := AValue;
|
|---|
| 1852 | end;
|
|---|
| 1853 |
|
|---|
| 1854 | procedure TSVGRadialGradient.SetR(AValue: TFloatWithCSSUnit);
|
|---|
| 1855 | begin
|
|---|
| 1856 | OrthoAttributeWithUnit['r'] := AValue;
|
|---|
| 1857 | end;
|
|---|
| 1858 |
|
|---|
| 1859 | procedure TSVGRadialGradient.SetFX(AValue: TFloatWithCSSUnit);
|
|---|
| 1860 | begin
|
|---|
| 1861 | HorizAttributeWithUnit['fx'] := AValue;
|
|---|
| 1862 | end;
|
|---|
| 1863 |
|
|---|
| 1864 | procedure TSVGRadialGradient.SetFY(AValue: TFloatWithCSSUnit);
|
|---|
| 1865 | begin
|
|---|
| 1866 | VerticalAttributeWithUnit['fy'] := AValue;
|
|---|
| 1867 | end;
|
|---|
| 1868 |
|
|---|
| 1869 | procedure TSVGRadialGradient.SetFR(AValue: TFloatWithCSSUnit);
|
|---|
| 1870 | begin
|
|---|
| 1871 | HorizAttributeWithUnit['fr'] := AValue;
|
|---|
| 1872 | end;
|
|---|
| 1873 |
|
|---|
| 1874 | constructor TSVGRadialGradient.Create(ADocument: TXMLDocument;
|
|---|
| 1875 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1876 | begin
|
|---|
| 1877 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1878 | Init(ADocument,'radialGradient',AUnits);
|
|---|
| 1879 | end;
|
|---|
| 1880 |
|
|---|
| 1881 | { TSVGStopGradient }
|
|---|
| 1882 |
|
|---|
| 1883 | function TSVGStopGradient.GetOffset: TFloatWithCSSUnit;
|
|---|
| 1884 | begin
|
|---|
| 1885 | result := AttributeWithUnit['offset'];
|
|---|
| 1886 | end;
|
|---|
| 1887 |
|
|---|
| 1888 | procedure TSVGStopGradient.SetOffset(AValue: TFloatWithCSSUnit);
|
|---|
| 1889 | begin
|
|---|
| 1890 | AttributeWithUnit['offset'] := AValue;
|
|---|
| 1891 | end;
|
|---|
| 1892 |
|
|---|
| 1893 | constructor TSVGStopGradient.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 1894 | ADataLink: TSVGDataLink);
|
|---|
| 1895 | begin
|
|---|
| 1896 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1897 | Init(ADocument,'stop',AUnits);
|
|---|
| 1898 | end;
|
|---|
| 1899 |
|
|---|
| 1900 | { TSVGDefine }
|
|---|
| 1901 |
|
|---|
| 1902 | constructor TSVGDefine.Create(ADocument: TXMLDocument; AUnits: TCSSUnitConverter;
|
|---|
| 1903 | ADataLink: TSVGDataLink);
|
|---|
| 1904 | begin
|
|---|
| 1905 | inherited Create(ADocument, AUnits, ADataLink);
|
|---|
| 1906 | FContent := TSVGContent.Create(ADocument,FDomElem,AUnits,ADataLink,Self);
|
|---|
| 1907 | end;
|
|---|
| 1908 |
|
|---|
| 1909 | constructor TSVGDefine.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 1910 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink);
|
|---|
| 1911 | begin
|
|---|
| 1912 | inherited Create(ADocument, AElement, AUnits, ADataLink);
|
|---|
| 1913 | FContent := TSVGContent.Create(ADocument,AElement,AUnits,ADataLink,Self);
|
|---|
| 1914 | end;
|
|---|
| 1915 |
|
|---|
| 1916 | destructor TSVGDefine.Destroy;
|
|---|
| 1917 | begin
|
|---|
| 1918 | FreeAndNil(FContent);
|
|---|
| 1919 | inherited Destroy;
|
|---|
| 1920 | end;
|
|---|
| 1921 |
|
|---|
| 1922 | procedure TSVGDefine.Recompute;
|
|---|
| 1923 | begin
|
|---|
| 1924 | inherited Recompute;
|
|---|
| 1925 | FContent.Recompute;
|
|---|
| 1926 | end;
|
|---|
| 1927 |
|
|---|
| 1928 | { TSVGContent }
|
|---|
| 1929 |
|
|---|
| 1930 | function TSVGContent.GetElement(AIndex: integer): TSVGElement;
|
|---|
| 1931 | begin
|
|---|
| 1932 | result := TSVGElement(FElements.Items[AIndex]);
|
|---|
| 1933 | end;
|
|---|
| 1934 |
|
|---|
| 1935 | function TSVGContent.GetElementCount: integer;
|
|---|
| 1936 | begin
|
|---|
| 1937 | result := FElements.Count;
|
|---|
| 1938 | end;
|
|---|
| 1939 |
|
|---|
| 1940 | function TSVGContent.GetUnits: TCSSUnitConverter;
|
|---|
| 1941 | begin
|
|---|
| 1942 | result := FUnits;
|
|---|
| 1943 | end;
|
|---|
| 1944 |
|
|---|
| 1945 | procedure TSVGContent.AppendElement(AElement: TSVGElement);
|
|---|
| 1946 | begin
|
|---|
| 1947 | FDomElem.AppendChild(AElement.DOMElement);
|
|---|
| 1948 | FElements.Add(AElement);
|
|---|
| 1949 | end;
|
|---|
| 1950 |
|
|---|
| 1951 | procedure TSVGContent.InsertElementBefore(AElement: TSVGElement;
|
|---|
| 1952 | ASuccessor: TSVGElement);
|
|---|
| 1953 | var idx: integer;
|
|---|
| 1954 | begin
|
|---|
| 1955 | idx := FElements.IndexOf(ASuccessor);
|
|---|
| 1956 | if idx <> -1 then
|
|---|
| 1957 | begin
|
|---|
| 1958 | FElements.Insert(idx,AElement);
|
|---|
| 1959 | FDomElem.InsertBefore(AElement.DOMElement, ASuccessor.DOMElement);
|
|---|
| 1960 | end
|
|---|
| 1961 | else
|
|---|
| 1962 | begin
|
|---|
| 1963 | FElements.Add(AElement);
|
|---|
| 1964 | FDomElem.AppendChild(ASuccessor.DOMElement);
|
|---|
| 1965 | end;
|
|---|
| 1966 | end;
|
|---|
| 1967 |
|
|---|
| 1968 | constructor TSVGContent.Create(ADocument: TXMLDocument; AElement: TDOMElement;
|
|---|
| 1969 | AUnits: TCSSUnitConverter; ADataLink: TSVGDataLink; ADataParent: TSVGElement);
|
|---|
| 1970 | var cur: TDOMNode;
|
|---|
| 1971 | begin
|
|---|
| 1972 | FDoc := ADocument;
|
|---|
| 1973 | FDomElem := AElement;
|
|---|
| 1974 | FDataLink := ADataLink;
|
|---|
| 1975 | FElements := TFPList.Create;
|
|---|
| 1976 | FUnits := AUnits;
|
|---|
| 1977 | cur := FDomElem.FirstChild;
|
|---|
| 1978 | while cur <> nil do
|
|---|
| 1979 | begin
|
|---|
| 1980 | if cur is TDOMElement then
|
|---|
| 1981 | FElements.Add(CreateSVGElementFromNode(
|
|---|
| 1982 | ADocument,TDOMElement(cur),FUnits,ADataLink,ADataParent));
|
|---|
| 1983 | cur := cur.NextSibling;
|
|---|
| 1984 | end;
|
|---|
| 1985 | end;
|
|---|
| 1986 |
|
|---|
| 1987 | destructor TSVGContent.Destroy;
|
|---|
| 1988 | var i:integer;
|
|---|
| 1989 | begin
|
|---|
| 1990 | for i := 0 to ElementCount-1 do
|
|---|
| 1991 | Element[i].free;
|
|---|
| 1992 | FreeAndNil(FElements);
|
|---|
| 1993 | inherited Destroy;
|
|---|
| 1994 | end;
|
|---|
| 1995 |
|
|---|
| 1996 | procedure TSVGContent.Recompute;
|
|---|
| 1997 | var
|
|---|
| 1998 | i: Integer;
|
|---|
| 1999 | begin
|
|---|
| 2000 | for i := 0 to ElementCount-1 do
|
|---|
| 2001 | Element[i].Recompute;
|
|---|
| 2002 | end;
|
|---|
| 2003 |
|
|---|
| 2004 | procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; x, y: single; AUnit: TCSSUnit);
|
|---|
| 2005 | var prevMatrix: TAffineMatrix;
|
|---|
| 2006 | begin
|
|---|
| 2007 | if (x<>0) or (y<>0) then
|
|---|
| 2008 | begin
|
|---|
| 2009 | prevMatrix := ACanvas2d.matrix;
|
|---|
| 2010 | ACanvas2d.translate(x,y);
|
|---|
| 2011 | Draw(ACanvas2d, AUnit);
|
|---|
| 2012 | ACanvas2d.matrix := prevMatrix;
|
|---|
| 2013 | end else
|
|---|
| 2014 | Draw(ACanvas2d, AUnit);
|
|---|
| 2015 | end;
|
|---|
| 2016 |
|
|---|
| 2017 | procedure TSVGContent.Draw(ACanvas2d: TBGRACanvas2D; AUnit: TCSSUnit);
|
|---|
| 2018 | var i: integer;
|
|---|
| 2019 | begin
|
|---|
| 2020 | for i := 0 to ElementCount-1 do
|
|---|
| 2021 | Element[i].Draw(ACanvas2d, AUnit);
|
|---|
| 2022 | end;
|
|---|
| 2023 |
|
|---|
| 2024 | function TSVGContent.AppendLine(x1, y1, x2, y2: single; AUnit: TCSSUnit
|
|---|
| 2025 | ): TSVGLine;
|
|---|
| 2026 | begin
|
|---|
| 2027 | result := TSVGLine.Create(FDoc,Units,FDataLink);
|
|---|
| 2028 | result.x1 := FloatWithCSSUnit(x1,AUnit);
|
|---|
| 2029 | result.y1 := FloatWithCSSUnit(y1,AUnit);
|
|---|
| 2030 | result.x2 := FloatWithCSSUnit(x2,AUnit);
|
|---|
| 2031 | result.y2 := FloatWithCSSUnit(y2,AUnit);
|
|---|
| 2032 | AppendElement(result);
|
|---|
| 2033 | end;
|
|---|
| 2034 |
|
|---|
| 2035 | function TSVGContent.AppendLine(p1, p2: TPointF; AUnit: TCSSUnit): TSVGLine;
|
|---|
| 2036 | begin
|
|---|
| 2037 | result := AppendLine(p1.x,p1.y,p2.x,p2.y,AUnit);
|
|---|
| 2038 | end;
|
|---|
| 2039 |
|
|---|
| 2040 | function TSVGContent.AppendCircle(cx, cy, r: single; AUnit: TCSSUnit
|
|---|
| 2041 | ): TSVGCircle;
|
|---|
| 2042 | begin
|
|---|
| 2043 | if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
|
|---|
| 2044 | begin
|
|---|
| 2045 | result := TSVGCircle.Create(FDoc,Units,FDataLink);
|
|---|
| 2046 | result.cx := FloatWithCSSUnit(Units.Convert(cx,AUnit,cuCustom,Units.DpiX),cuCustom);
|
|---|
| 2047 | result.cy := FloatWithCSSUnit(Units.Convert(cy,AUnit,cuCustom,Units.DpiY),cuCustom);
|
|---|
| 2048 | result.r := FloatWithCSSUnit(Units.Convert(r,AUnit,cuCustom,Units.DpiX),cuCustom);
|
|---|
| 2049 | result.transform:= Units.DpiScaleTransform;
|
|---|
| 2050 | AppendElement(result);
|
|---|
| 2051 | end else
|
|---|
| 2052 | begin
|
|---|
| 2053 | result := TSVGCircle.Create(FDoc,Units,FDataLink);
|
|---|
| 2054 | result.cx := FloatWithCSSUnit(cx,AUnit);
|
|---|
| 2055 | result.cy := FloatWithCSSUnit(cy,AUnit);
|
|---|
| 2056 | result.r := FloatWithCSSUnit(r,AUnit);
|
|---|
| 2057 | AppendElement(result);
|
|---|
| 2058 | end;
|
|---|
| 2059 | end;
|
|---|
| 2060 |
|
|---|
| 2061 | function TSVGContent.AppendCircle(c: TPointF; r: single; AUnit: TCSSUnit
|
|---|
| 2062 | ): TSVGCircle;
|
|---|
| 2063 | begin
|
|---|
| 2064 | result := AppendCircle(c.x,c.y,r,AUnit);
|
|---|
| 2065 | end;
|
|---|
| 2066 |
|
|---|
| 2067 | function TSVGContent.AppendEllipse(cx, cy, rx, ry: single; AUnit: TCSSUnit
|
|---|
| 2068 | ): TSVGEllipse;
|
|---|
| 2069 | begin
|
|---|
| 2070 | result := TSVGEllipse.Create(FDoc,Units,FDataLink);
|
|---|
| 2071 | result.cx := FloatWithCSSUnit(cx,AUnit);
|
|---|
| 2072 | result.cy := FloatWithCSSUnit(cy,AUnit);
|
|---|
| 2073 | result.rx := FloatWithCSSUnit(rx,AUnit);
|
|---|
| 2074 | result.ry := FloatWithCSSUnit(ry,AUnit);
|
|---|
| 2075 | AppendElement(result);
|
|---|
| 2076 | end;
|
|---|
| 2077 |
|
|---|
| 2078 | function TSVGContent.AppendEllipse(c, r: TPointF; AUnit: TCSSUnit): TSVGEllipse;
|
|---|
| 2079 | begin
|
|---|
| 2080 | result := AppendEllipse(c.x,c.y,r.x,r.y,AUnit);
|
|---|
| 2081 | end;
|
|---|
| 2082 |
|
|---|
| 2083 | function TSVGContent.AppendPath(data: string; AUnit: TCSSUnit): TSVGPath;
|
|---|
| 2084 | var tempPath: TBGRAPath;
|
|---|
| 2085 | begin
|
|---|
| 2086 | if AUnit <> cuCustom then
|
|---|
| 2087 | begin
|
|---|
| 2088 | tempPath := TBGRAPath.Create(data);
|
|---|
| 2089 | result := AppendPath(tempPath, AUnit);
|
|---|
| 2090 | tempPath.Free;
|
|---|
| 2091 | end else
|
|---|
| 2092 | begin
|
|---|
| 2093 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
|---|
| 2094 | result.d := data;
|
|---|
| 2095 | AppendElement(result);
|
|---|
| 2096 | end;
|
|---|
| 2097 | end;
|
|---|
| 2098 |
|
|---|
| 2099 | function TSVGContent.AppendPath(path: TBGRAPath; AUnit: TCSSUnit): TSVGPath;
|
|---|
| 2100 | begin
|
|---|
| 2101 | if (AUnit <> cuCustom) and (Units.DpiScaleX <> Units.DpiScaleY) then
|
|---|
| 2102 | begin
|
|---|
| 2103 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
|---|
| 2104 | result.path.scale(Units.Convert(1,AUnit,cuCustom,Units.DpiX));
|
|---|
| 2105 | path.copyTo(result.path);
|
|---|
| 2106 | result.transform := Units.DpiScaleTransform;
|
|---|
| 2107 | AppendElement(result);
|
|---|
| 2108 | end else
|
|---|
| 2109 | begin
|
|---|
| 2110 | result := TSVGPath.Create(FDoc,Units,FDataLink);
|
|---|
| 2111 | result.path.scale(Units.ConvertWidth(1,AUnit,cuCustom));
|
|---|
| 2112 | path.copyTo(result.path);
|
|---|
| 2113 | AppendElement(result);
|
|---|
| 2114 | end;
|
|---|
| 2115 | end;
|
|---|
| 2116 |
|
|---|
| 2117 | function TSVGContent.AppendPolygon(const points: array of single;
|
|---|
| 2118 | AUnit: TCSSUnit): TSVGPolypoints;
|
|---|
| 2119 | var
|
|---|
| 2120 | pts: ArrayOfTPointF;
|
|---|
| 2121 | i: integer;
|
|---|
| 2122 | begin
|
|---|
| 2123 | result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
|
|---|
| 2124 | setlength(pts, length(points) div 2);
|
|---|
| 2125 | for i := 0 to high(pts) do
|
|---|
| 2126 | pts[i] := Units.ConvertCoord(PointF(points[i shl 1],points[(i shl 1)+1]),AUnit,cuCustom);
|
|---|
| 2127 | result.pointsF := pts;
|
|---|
| 2128 | AppendElement(result);
|
|---|
| 2129 | end;
|
|---|
| 2130 |
|
|---|
| 2131 | function TSVGContent.AppendPolygon(const points: array of TPointF;
|
|---|
| 2132 | AUnit: TCSSUnit): TSVGPolypoints;
|
|---|
| 2133 | var
|
|---|
| 2134 | pts: ArrayOfTPointF;
|
|---|
| 2135 | i: integer;
|
|---|
| 2136 | begin
|
|---|
| 2137 | result := TSVGPolypoints.Create(FDoc,FUnits,true,FDataLink);
|
|---|
| 2138 | setlength(pts, length(points));
|
|---|
| 2139 | for i := 0 to high(pts) do
|
|---|
| 2140 | pts[i] := Units.ConvertCoord(points[i],AUnit,cuCustom);
|
|---|
| 2141 | result.pointsF := pts;
|
|---|
| 2142 | AppendElement(result);
|
|---|
| 2143 | end;
|
|---|
| 2144 |
|
|---|
| 2145 | function TSVGContent.AppendRect(x, y, width, height: single; AUnit: TCSSUnit
|
|---|
| 2146 | ): TSVGRectangle;
|
|---|
| 2147 | begin
|
|---|
| 2148 | result := TSVGRectangle.Create(FDoc,Units,FDataLink);
|
|---|
| 2149 | result.x := FloatWithCSSUnit(x,AUnit);
|
|---|
| 2150 | result.y := FloatWithCSSUnit(y,AUnit);
|
|---|
| 2151 | result.width := FloatWithCSSUnit(width,AUnit);
|
|---|
| 2152 | result.height := FloatWithCSSUnit(height,AUnit);
|
|---|
| 2153 | AppendElement(result);
|
|---|
| 2154 | end;
|
|---|
| 2155 |
|
|---|
| 2156 | function TSVGContent.AppendRect(origin, size: TPointF; AUnit: TCSSUnit
|
|---|
| 2157 | ): TSVGRectangle;
|
|---|
| 2158 | begin
|
|---|
| 2159 | result := AppendRect(origin.x,origin.y,size.x,size.y,AUnit);
|
|---|
| 2160 | end;
|
|---|
| 2161 |
|
|---|
| 2162 | function TSVGContent.AppendText(x, y: single; AText: string; AUnit: TCSSUnit
|
|---|
| 2163 | ): TSVGText;
|
|---|
| 2164 | begin
|
|---|
| 2165 | result := TSVGText.Create(FDoc,Units,FDataLink);
|
|---|
| 2166 | result.x := FloatWithCSSUnit(x,AUnit);
|
|---|
| 2167 | result.y := FloatWithCSSUnit(y,AUnit);
|
|---|
| 2168 | result.SimpleText:= AText;
|
|---|
| 2169 | AppendElement(result);
|
|---|
| 2170 | end;
|
|---|
| 2171 |
|
|---|
| 2172 | function TSVGContent.AppendText(origin: TPointF; AText: string; AUnit: TCSSUnit
|
|---|
| 2173 | ): TSVGText;
|
|---|
| 2174 | begin
|
|---|
| 2175 | result := AppendText(origin.x,origin.y,AText,AUnit);
|
|---|
| 2176 | end;
|
|---|
| 2177 |
|
|---|
| 2178 | function TSVGContent.AppendRoundRect(x, y, width, height, rx, ry: single;
|
|---|
| 2179 | AUnit: TCSSUnit): TSVGRectangle;
|
|---|
| 2180 | begin
|
|---|
| 2181 | result := TSVGRectangle.Create(FDoc,Units,FDataLink);
|
|---|
| 2182 | result.x := FloatWithCSSUnit(x,AUnit);
|
|---|
| 2183 | result.y := FloatWithCSSUnit(y,AUnit);
|
|---|
| 2184 | result.width := FloatWithCSSUnit(width,AUnit);
|
|---|
| 2185 | result.height := FloatWithCSSUnit(height,AUnit);
|
|---|
| 2186 | result.rx := FloatWithCSSUnit(rx,AUnit);
|
|---|
| 2187 | result.ry := FloatWithCSSUnit(ry,AUnit);
|
|---|
| 2188 | AppendElement(result);
|
|---|
| 2189 | end;
|
|---|
| 2190 |
|
|---|
| 2191 | function TSVGContent.AppendRoundRect(origin, size, radius: TPointF;
|
|---|
| 2192 | AUnit: TCSSUnit): TSVGRectangle;
|
|---|
| 2193 | begin
|
|---|
| 2194 | result := AppendRoundRect(origin.x,origin.y,size.x,size.y,radius.x,radius.y,AUnit);
|
|---|
| 2195 | end;
|
|---|
| 2196 |
|
|---|
| 2197 | end.
|
|---|
| 2198 |
|
|---|